o x[h@stdZddlZddlZddlZddlZddlZddlmZddlm Z m Z ddl m Z e eZdZGdddZdS) z0gpg.py - Collection of gpg key related functionsN)TemporaryDirectory)DictOptional)subp GNUPGHOMEc@seZdZddZddZedeeeffddZdd Z d"d d Z d ede efddZ d edefddZ d#dedefddZd$d ededd fddZd edd fddZ d%dedede efddZd"d d!Zd S)&GPGcCsd|_i|_t|_dS)NF) gpg_started_envrtemp_dirselfr //usr/lib/python3/dist-packages/cloudinit/gpg.py__init__s z 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)r rHOMEr namer r r renv"s  zGPG.envcCs |dSr)cleanup)r exc_typ exc_value tracebackr r r__exit__1s z GPG.__exit__NcCs4||jrtj|jjr|jdSdSdS)z0cleanup the gpg temporary directory and kill gpgN)kill_gpgr ospathisdirrrr r r rr4sz GPG.cleanupkeyc CsVztjddd|gd|jdjWStjy*}ztd||WYd}~dSd}~ww)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 r z --dearmorF)datadecoder#)rrr%)r rr r rdearmorGs z GPG.dearmorFkey_filecCsLgd}|s |d||tj||jdd\}}|r$td|||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 )r z --no-optionsz--with-fingerprintz--no-default-keyringz --list-keysz --keyringz --with-colonsT)r#r"r$)appendrrr'warning)r r/ human_outputcmdr%stderrr r r list_keysPs  z GPG.list_keysr7 keyserverc Cstd||d}d}t|pg} |d7}ztjddd|d |gd|jd td |||WdStjyF}z|}WYd}~nd}~wwzt|}td |j|t |Wnt yq}z t d ||||f|d}~wwq)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'rNTr7r z--no-ttyz--keyserver=%sz --recv-keysr!z/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&next exit_codetimesleep StopIteration ValueError) r rr8retriestrynumr*sleepsenaplenr r rrecv_keyjs^   z GPG.recv_keyc CsZztjdddd|gd|jdWdStjy,}ztd||WYd}~dSd}~ww) z0Delete the specified key from the local gpg ringr z--batchz--yesz --delete-keysTr!zFailed delete key "%s": %sN)rrr&r'r1r)r r r delete_keys  zGPG.delete_keykeyserver.ubuntu.comkeyidc Csj||}|s3z%z|j||d||}Wnty$td|wW|||S||w|S)zget gpg keyid from keyserver)r8zFailed to obtain gpg key %s)r+rEr?r' exceptionrF)r rHr8armourr r r getkeybyids     zGPG.getkeybyidc CszK|jsWdStdrtjgdd|jdj}WdStjgddddgd j}td |}d d |D}|r=td ||D] }t |t j q?WdStj ye}z td|WYd}~dSd}~ww)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)rLz--killallTr!) psz-ozppid,pid-CkeyboxdrOdirmngrrOz gpg-agentrr7)r"rcsz(?P\d+)\s+(?P\d+)cSs$g|]}|ddkrt|dqS)r1r7)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&r1)r gpg_process_outgpg_pids root_gpg_pidsgpg_pidrCr r rrsF  z GPG.kill_gpg)rN)F)r6)rG)__name__ __module__ __qualname__rrpropertyrstrrrrrr+r.r5rErFrKrr r r rrs*   7  r)__doc__loggingrrYr\r<tempfilertypingrr cloudinitr getLoggerrbr'rrr r r rs