a '¡Dgúã@stdZddlZddlZddlZddlZddlZddlmZddlm Z m Z ddl m Z e  e¡ZdZGdd„dƒZdS) z0gpg.py - Collection of gpg key related functionséN)ÚTemporaryDirectory)ÚDictÚOptional)ÚsubpZ GNUPGHOMEc@sÌeZdZdd„Zdd„Zeeeefdœdd„ƒZdd „Z d dœd d „Z ee ed œdd„Z eed œdd„Z d"eedœdd„Zd#eed dœdd„Zed d œdd„Zd$eee edœdd„Zd dœd d!„Zd S)%ÚGPGcCsd|_i|_tƒ|_dS)NF)Ú gpg_startedÚ_envrÚtemp_dir©Úself©r ú1/usr/lib/python3.9/site-packages/cloudinit/gpg.pyÚ__init__sz GPG.__init__cCs|S©Nr r r r r Ú __enter__sz GPG.__enter__)ÚreturncCs&|jr |jSd|_t|jji|_|jS)awhen this env property gets invoked, set up our temporary directory, and also set gpg_started to tell the cleanup() method whether or not why put this here and not in __init__? pytest seems unhappy and it's not obvious how to work around it T)rrÚHOMEr Únamer r r r Úenv"s zGPG.envcCs | ¡dSr)Úcleanup)r Zexc_typÚ exc_valueÚ tracebackr r r Ú__exit__1sz GPG.__exit__NcCs,| ¡|jr(tj |jj¡r(|j ¡dS)z0cleanup the gpg temporary directory and kill gpgN)Úkill_gpgr ÚosÚpathÚisdirrrr r r r r4sz GPG.cleanup)Úkeyrc CsXztjddd|gd|jd�jWStjyR}zt d||¡WYd}~n d}~00dS)z*Export gpg key, armoured key gets returnedÚgpgz--exportz--armourT©ÚcaptureÚ update_envú&Failed to export armoured key "%s": %sN)rrÚstdoutÚProcessExecutionErrorÚLOGÚdebug©r rÚerrorr r r Ú export_armour:s ý $zGPG.export_armourcCstjddg|d|jd�jS)z†Dearmor gpg key, dearmored key gets returned note: man gpg(1) makes no mention of an --armour spelling, only --armor rz --dearmorF)ÚdataÚdecoder!)rrr#)r rr r r ÚdearmorGsÿz GPG.dearmorF)Úkey_filercCsLgd¢}|s| d¡| |¡tj||jdd�\}}|rHt d||¡|S)zòList keys from a keyring with fingerprints. Default to a stable machine parseable format. @param key_file: a string containing a filepath to a key @param human_output: return output intended for human parsing )rz --no-optionsz--with-fingerprintz--no-default-keyringz --list-keysz --keyringz --with-colonsT)r!r r")Úappendrrr%Úwarning)r r-Z human_outputÚcmdr#Ústderrr r r Ú list_keysPs  ÿz GPG.list_keys©ér4)rÚ keyserverrc Csôt d||¡d}d}t|pgƒ}|d7}z6tjddd|d|gd |jd �t d |||¡WdStjyŠ}z|}WYd}~n d}~00z&t|ƒ}t d |j|¡t  |¡Wq"t yì}z"t d ||||fƒ|‚WYd}~q"d}~00q"dS)aÙReceive gpg key from the specified keyserver. Retries are done by default because keyservers can be unreliable. Additionally, there is no way to determine the difference between a non-existent key and a failure. In both cases gpg (at least 2.2.4) exits with status 2 and stderr: "keyserver receive failed: No data" It is assumed that a key provided to cloud-init exists on the keyserver so re-trying makes better sense than failing. @param key: a string key fingerprint (as passed to gpg --recv-keys). @param keyserver: the keyserver to request keys from. @param retries: an iterable of sleep lengths for retries. Use None to indicate no retries.z&Importing key '%s' from keyserver '%s'rNr4rz--no-ttyz--keyserver=%sz --recv-keysTrz/Imported key '%s' from keyserver '%s' on try %dz6Import failed with exit code %d, will try again in %ssz@Failed to import key '%s' from keyserver '%s' after %d tries: %s) r%r&Úiterrrr$ÚnextZ exit_codeÚtimeÚsleepÚ StopIterationÚ ValueError) r rr5ZretriesZtrynumr(ZsleepsÚeZnaplenr r r Úrecv_keyjsR û÷ üý ÿÿýz GPG.recv_keyc CsZz tjdddd|gd|jd�Wn4tjyT}zt d||¡WYd}~n d}~00dS) z0Delete the specified key from the local gpg ringrz--batchz--yesz --delete-keysTrzFailed delete key "%s": %sN)rrr$r%r/r'r r r Ú delete_key¡s ý zGPG.delete_keyúkeyserver.ubuntu.com)Úkeyidr5rc Csl| |¡}|shzLz|j||d�| |¡}Wn tyLt d|¡‚Yn0W| |¡n | |¡0|S)zget gpg keyid from keyserver)r5zFailed to obtain gpg key %s)r)r=r;r%Ú exceptionr>)r r@r5Zarmourr r r Ú getkeybyid¬s    zGPG.getkeybyidc CsÈz�|jsWdSt d¡r2tjgd¢d|jd�j}n\tjgd¢dddgd �j}t d |¡}d d „|Dƒ}|rvt d |¡|D]}t   |t j ¡qzWn2tj yÂ}zt d|¡WYd}~n d}~00dS)akilling with gpgconf is best practice, but when it isn't available failover is possible GH: 4344 - stop gpg-agent/dirmgr daemons spawned by gpg key imports. Daemons spawned by cloud-config.service on systemd v253 report (running) NÚgpgconf)rCz--killÚallTr) Zpsz-ozppid,pidú-CZkeyboxdrEZdirmngrrEz gpg-agentrr4)r Zrcsz(?P\d+)\s+(?P\d+)cSs$g|]}|ddkrt|dƒ‘qS)rÚ1r4)Úint)Ú.0Úpidr r r Ú âsz GPG.kill_gpg..z&Killing gpg-agent and dirmngr pids: %sz"Failed to clean up gpg process: %s)rrÚwhichrr#ÚreÚfindallr%r&rÚkillÚsignalÚSIGKILLr$r/)r Zgpg_process_outZgpg_pidsZ root_gpg_pidsZgpg_pidr<r r r r¾s8 ý  óÿÿÿz GPG.kill_gpg)F)r3)r?)Ú__name__Ú __module__Ú __qualname__rrÚpropertyrÚstrrrrrr)r,r2r=r>rBrr r r r rs"  7 ÿþ r)Ú__doc__ZloggingrrLrOr8ZtempfilerÚtypingrrZ cloudinitrZ getLoggerrQr%rrr r r r Ús