
    }f                         d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZ  ej                  e      ZdZ G d d      Zy)	z0gpg.py - Collection of gpg key related functions    N)TemporaryDirectory)DictOptional)subp	GNUPGHOMEc                       e Zd Zd Zd Zedeeef   fd       Zd Z	ddZ
dedee   fd	Zdedefd
ZddedefdZddededdfdZdeddfdZ	 ddededee   fdZddZy)GPGc                 >    d| _         i | _        t               | _        y )NF)gpg_started_envr   temp_dirselfs    //usr/lib/python3/dist-packages/cloudinit/gpg.py__init__zGPG.__init__   s     	*,    c                     | S N r   s    r   	__enter__zGPG.__enter__   s    r   returnc                     | j                   r| j                   S d| _        t        | j                  j                  i| _         | j                   S )a  when 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   namer   s    r   envzGPG.env"   s=     99994==--.	yyr   c                 $    | j                          y r   )cleanup)r   exc_typ	exc_value	tracebacks       r   __exit__zGPG.__exit__1   s    r   Nc                     | j                          | j                  rOt        j                  j	                  | j                  j
                        r| j                  j                          yyy)z0cleanup the gpg temporary directory and kill gpgN)kill_gpgr   ospathisdirr   r   r   s    r   r   zGPG.cleanup4   sB    ==RWW]]4==+=+=>MM!!# ?=r   keyc                     	 t        j                   ddd|gd| j                        j                  S # t         j                  $ r!}t        j                  d||       Y d}~yd}~ww xY w)z*Export gpg key, armoured key gets returnedgpgz--exportz--armourTcapture
update_env&Failed to export armoured key "%s": %sN)r   r   stdoutProcessExecutionErrorLOGdebugr   r'   errors      r   export_armourzGPG.export_armour:   sg    	L99
J488 f	
 )) 	LII>UKK	Ls   /2 A&A!!A&c                 `    t        j                   ddg|d| j                        j                  S )zDearmor gpg key, dearmored key gets returned

        note: man gpg(1) makes no mention of an --armour spelling, only --armor
        r)   z	--dearmorF)datadecoder,   )r   r   r.   )r   r'   s     r   dearmorzGPG.dearmorG   s,    
 yyK s5TXX

&	r   key_filec                     g d}|s|j                  d       |j                  |       t        j                  || j                  d      \  }}|rt        j	                  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-   )appendr   r   r0   warning)r   r9   human_outputcmdr.   stderrs         r   	list_keyszGPG.list_keysP   s]    
 JJ'

83488TJKK8(F r   	keyserverc                    t         j                  d||       d}d}t        |xs g       }	 |dz  }	 t        j                  ddd|z  d	|gd| j                  
       t         j                  d|||       y# t        j
                  $ r}|}Y d}~nd}~ww xY w	 t        |      }t         j                  d|j                  |       t        j                  |       n$# t        $ r}t        d||||fz        |d}~ww xY w)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'r   NT   r)   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)r0   r1   iterr   r   r/   next	exit_codetimesleepStopIteration
ValueError)	r   r'   rA   retriestrynumr3   sleepsenaplens	            r   recv_keyzGPG.recv_keyj   s    			:CKgm$aKF		"(94% !#xx
 		E	 -- f		LOO
 

6"   ),/FE+JK ? s1   AA5 5BBBAC 	C;#C66C;c                     	 t        j                   dddd|gd| j                         y# t         j                  $ r!}t        j	                  d||       Y d}~yd}~ww xY w)	z0Delete the specified key from the local gpg ringr)   z--batchz--yesz--delete-keysTr*   zFailed delete key "%s": %sN)r   r   r/   r0   r<   r2   s      r   
delete_keyzGPG.delete_key   sZ    	BII	7OSA88
 )) 	BKK4c5AA	Bs   '* AAAkeyidc                    | j                  |      }|s9	 | j                  ||       | j                  |      }	 | j                  |       |S |S # t        $ r t        j	                  d|        w xY w# | j                  |       w xY w)zget gpg keyid from keyserver)rA   zFailed to obtain gpg key %s)r4   rP   rJ   r0   	exceptionrR   )r   rS   rA   armours       r   
getkeybyidzGPG.getkeybyid   s     ##E*	'ey9++E2 &v  ;UC &s   $A !A00A3 3Bc                 d   	 | j                   syt        j                  d      r/t        j                  g dd| j                        j                  }yt        j                  g ddddg	      j                  }t        j                  d
|      }|D cg c]  }|d   dk(  st        |d          }}|rt        j                  d|       |D ]&  }t        j                  |t        j                         ( yc c}w # t        j                  $ r }t        j                  d|       Y d}~yd}~ww xY w)a  killing 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)rY   z--killallTr*   )	psz-ozppid,pid-Ckeyboxdr\   dirmngrr\   z	gpg-agentr   rC   )r+   rcsz(?P<ppid>\d+)\s+(?P<pid>\d+)1z&Killing gpg-agent and dirmngr pids: %sz"Failed to clean up gpg process: %s)r   r   whichr   r.   refindallintr0   r1   r$   killsignalSIGKILLr/   r<   )r   gpg_process_outgpg_pidspidroot_gpg_pidsgpg_pidrN   s          r   r#   zGPG.kill_gpg   s   &	A##zz)$"&))0 #xx# &	   #'))
 !A# &   ::3_ ,4!$'s1v}CAK! ! !II@-  - 5GGGGV^^45! )) 	AKK<a@@	As=   C< AC< A C< C7!C71AC< 7C< <D/D**D/)r   N)F))rC   rC   )zkeyserver.ubuntu.com)__name__
__module____qualname__r   r   propertyr   strr   r!   r   r   r4   r8   r@   rP   rR   rW   r#   r   r   r   r	   r	      s    -
 T#s(^  $ # 3 3 # c 45C 5C 5D 5n	Bc 	Bd 	B ,B%(	#$.Ar   r	   )__doc__loggingr$   rb   rf   rG   tempfiler   typingr   r   	cloudinitr   	getLoggerrm   r0   r   r	   r   r   r   <module>rx      sG    7  	 	   ' ! g!SA SAr   