a 'Dg@stdZddlZddlZddlZddlZddlZddlmZddlm Z m Z ddl m Z e eZdZGdddZdS) z0gpg.py - Collection of gpg key related functionsN)TemporaryDirectory)DictOptional)subpZ GNUPGHOMEc@seZdZddZddZeeeefdddZdd Z d dd d Z ee ed ddZ eed ddZ d"eedddZd#eed dddZed d ddZd$eee edddZd dd d!Zd S)%GPGcCsd|_i|_t|_dS)NF) gpg_started_envrtemp_dirselfr 1/usr/lib/python3.9/site-packages/cloudinit/gpg.py__init__sz GPG.__init__cCs|SNr 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)rrHOMEr 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|jjr(|jdS)z0cleanup the gpg temporary directory and kill gpgN)kill_gpgr ospathisdirrrr r r r r4sz GPG.cleanup)keyrc CsXztjddd|gd|jdjWStjyR}ztd||WYd}~n d}~00dS)z*Export gpg key, armoured key gets returnedgpgz--exportz--armourTcapture update_env&Failed to export armoured key "%s": %sN)rrstdoutProcessExecutionErrorLOGdebugr rerrorr r r export_armour:s  $zGPG.export_armourcCstjddg|d|jdjS)zDearmor gpg key, dearmored key gets returned note: man gpg(1) makes no mention of an --armour spelling, only --armor rz --dearmorF)datadecoder!)rrr#)r rr r r dearmorGsz GPG.dearmorF)key_filercCsLgd}|s|d||tj||jdd\}}|rHtd|||S)zList 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_outputcmdr#stderrr r r list_keysPs  z GPG.list_keysr4)r keyserverrc Cstd||d}d}t|pg}|d7}z6tjddd|d|gd |jd td |||WdStjy}z|}WYd}~n d}~00z&t|}td |j|t |Wq"t y}z"t d ||||f|WYd}~q"d}~00q"dS)aReceive 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_codetimesleep StopIteration ValueError) r rr5ZretriesZtrynumr(ZsleepseZnaplenr r r recv_keyjsR   z GPG.recv_keyc CsZz tjdddd|gd|jdWn4tjyT}ztd||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_keys  zGPG.delete_keykeyserver.ubuntu.com)keyidr5rc Csl||}|shzLz|j||d||}Wn tyLtd|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 getkeybyids    zGPG.getkeybyidc Csz|jsWdStdr2tjgdd|jdj}n\tjgddddgd j}td |}d d |D}|rvtd ||D]}t |t j qzWn2tj y}ztd|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) Ngpgconf)rCz--killallTr) Zpsz-ozppid,pid-CZkeyboxdrEZdirmngrrEz gpg-agentrr4)r Zrcsz(?P\d+)\s+(?P\d+)cSs$g|]}|ddkrt|dqS)r1r4)int).0pidr r r sz GPG.kill_gpg..z&Killing gpg-agent and dirmngr pids: %sz"Failed to clean up gpg process: %s)rrwhichrr#refindallr%r&rkillsignalSIGKILLr$r/)r Zgpg_process_outZgpg_pidsZ root_gpg_pidsZgpg_pidr<r r r rs8   z GPG.kill_gpg)F)r3)r?)__name__ __module__ __qualname__rrpropertyrstrrrrrr)r,r2r=r>rBrr r r r rs"  7  r)__doc__ZloggingrrLrOr8ZtempfilertypingrrZ cloudinitrZ getLoggerrQr%rrr r r r s