x[hdZddlZddlZddlZddlZddlZddlmZddlm Z m Z ddl m Z ejeZdZGddZy) z0gpg.py - Collection of gpg key related functionsN)TemporaryDirectory)DictOptional)subp GNUPGHOMEceZdZdZdZedeeeffdZdZ ddZ dede efd Z dedefd Z dd edefd Zdded eddfdZdeddfdZ dded ede efdZddZy)GPGc>d|_i|_t|_y)NF) gpg_started_envrtemp_dirselfs //usr/lib/python3/dist-packages/cloudinit/gpg.py__init__z GPG.__init__s  *, c|SNrs r __enter__z GPG.__enter__s rreturnc|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 r HOMEr namers renvzGPG.env"s= 9999 4==--. yyrc$|jyr)cleanup)rexc_typ exc_value tracebacks r__exit__z GPG.__exit__1s  rNc|j|jrOtjj |jj r|jj yyy)z0cleanup the gpg temporary directory and kill gpgN)kill_gpgr ospathisdirrrrs rrz GPG.cleanup4sB  ==RWW]]4==+=+=> MM ! ! #?=rkeyc tjddd|gd|jjS#tj$r!}tj d||Yd}~yd}~wwxYw)z*Export gpg key, armoured key gets returnedgpgz--exportz--armourTcapture update_env&Failed to export armoured key "%s": %sN)rrstdoutProcessExecutionErrorLOGdebugrr'errors r export_armourzGPG.export_armour:sg L99 J488f   )) L II>U K K Ls/2A&A!!A&c`tjddg|d|jjS)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.)rr's rdearmorz GPG.dearmorGs, yy K s5TXX & rkey_filecgd}|s|jd|j|tj||jd\}}|rtj d|||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-)appendrrr0warning)rr9 human_outputcmdr.stderrs r list_keysz GPG.list_keysPs]  JJ ' 83488TJ  KK8(F  r keyserverctjd||d}d}t|xsg} |dz } tjddd|zd |gd|j tjd |||y#tj $r }|}Yd}~nd}~wwxYw t |}tjd |j|tj|n$#t$r}td ||||fz|d}~wwxYw)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'rNTr)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) r0r1iterrrr/next exit_codetimesleep StopIteration ValueError) rr'rAretriestrynumr3sleepsenaplens rrecv_keyz GPG.recv_keyjs :CKgm$ aKF  "(94% !#xx  E  --   f LOO  6"   ),/FE+JK ?s1AA55BBBAC C;#C66C;c tjdddd|gd|jy#tj$r!}tj d||Yd}~yd}~wwxYw) z0Delete the specified key from the local gpg ringr)z--batchz--yesz --delete-keysTr*zFailed delete key "%s": %sN)rrr/r0r<r2s r delete_keyzGPG.delete_keysZ B II 7OSA88  )) B KK4c5 A A Bs'*AAAkeyidc|j|}|s9 |j|||j|} |j ||S|S#t$rtj d|wxYw#|j |wxYw)zget gpg keyid from keyserver)rAzFailed to obtain gpg key %s)r4rPrJr0 exceptionrR)rrSrAarmours r getkeybyidzGPG.getkeybyids##E* ' ey 9++E2& v   ;UC  &s$A!A00A33Bcd |jsytjdr/tjgdd|jj}ytjgddddg j}t j d |}|Dcgc]}|dd k(s t|d}}|rtjd ||D]&}tj|tj(ycc}w#tj$r }tjd |Yd}~yd}~wwxYw)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)rYz--killallTr*) psz-ozppid,pid-Ckeyboxdr\dirmngrr\z gpg-agentrrC)r+rcsz(?P\d+)\s+(?P\d+)1z&Killing gpg-agent and dirmngr pids: %sz"Failed to clean up gpg process: %s)r rwhichrr.refindallintr0r1r$killsignalSIGKILLr/r<)rgpg_process_outgpg_pidspid root_gpg_pidsgpg_pidrNs rr#z GPG.kill_gpgs& A##zz)$"&))0 #xx#&  #')) !A#& ::3_,4!$'s1v}CAK! !!II@- -5GGGGV^^45!)) A KKrxsG7 '!g!SASAr