
"T`{5                 @   s@  d  d l  Z  d  d l Z d  d l m Z d  d l m Z e j e  Z d Z	 d: Z
 d Z d e e  d Z Gd d   d e  Z Gd  d!   d! e  Z d" d#   Z d$ d%   Z d& d'   Z d( d)   Z e	 d* d+  Z d d, d-  Z Gd. d/   d/ e  Z d0 d1   Z d2 d3   Z d4 d5   Z e	 d6 d7  Z d8 d9   Z d S);    N)log)utilz/etc/ssh/sshd_configdsarsaecdsaed25519(ecdsa-sha2-nistp256-cert-v01@openssh.comecdsa-sha2-nistp256(ecdsa-sha2-nistp384-cert-v01@openssh.comecdsa-sha2-nistp384(ecdsa-sha2-nistp521-cert-v01@openssh.comecdsa-sha2-nistp521+sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"sk-ecdsa-sha2-nistp256@openssh.com#sk-ssh-ed25519-cert-v01@openssh.comsk-ssh-ed25519@openssh.comssh-dss-cert-v01@openssh.comssh-dss ssh-ed25519-cert-v01@openssh.comssh-ed25519ssh-rsa-cert-v01@openssh.comssh-rsassh-xmss-cert-v01@openssh.comssh-xmss@openssh.com   zno-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"$USER\" rather than the user \"$DISABLE_USER\".';echo;sleep 10;exit "c               @   s@   e  Z d  Z d d d d d d  Z d d   Z d d   Z d S)AuthKeyLineNc             C   s1   | |  _  | |  _ | |  _ | |  _ | |  _ d  S)N)base64commentoptionskeytypesource)selfr!   r    r   r   r    r#   4/usr/lib/python3/dist-packages/cloudinit/ssh_util.py__init__E   s
    				zAuthKeyLine.__init__c             C   s   |  j  o |  j S)N)r   r    )r"   r#   r#   r$   validM   s    zAuthKeyLine.validc             C   s   g  } |  j  r | j |  j   |  j r8 | j |  j  |  j rQ | j |  j  |  j rj | j |  j  | sw |  j Sd j |  Sd  S)N )r   appendr    r   r   r!   join)r"   toksr#   r#   r$   __str__P   s    				zAuthKeyLine.__str__)__name__
__module____qualname__r%   r&   r+   r#   r#   r#   r$   r   D   s   r   c               @   s1   e  Z d  Z d Z d d   Z d d d  Z d S)AuthKeyLineParsera  
    AUTHORIZED_KEYS FILE FORMAT
     AuthorizedKeysFile specifies the file containing public keys for public
     key authentication; if none is specified, the default is
     ~/.ssh/authorized_keys.  Each line of the file contains one key (empty
     (because of the size of the public key encoding) up to a limit of 8 kilo-
     bytes, which permits DSA keys up to 8 kilobits and RSA keys up to 16
     kilobits.  You don't want to type them in; instead, copy the
     identity.pub, id_dsa.pub, or the id_rsa.pub file and edit it.

     sshd enforces a minimum RSA key modulus size for protocol 1 and protocol
     2 keys of 768 bits.

     The options (if present) consist of comma-separated option specifica-
     tions.  No spaces are permitted, except within double quotes.  The fol-
     lowing option specifications are supported (note that option keywords are
     case-insensitive):
    c             C   s   d } d } x | t  |  k  r | s7 | | d	 k r | | } | d t  |  k rb | d } P| | d } | d k r | d k r | d } n | d k r | } | d } q W| d |  } | | d  j   } | | f S)
z
        The options (if present) consist of comma-separated option specifica-
         tions.  No spaces are permitted, except within double quotes.
         Note that option keywords are case-insensitive.
        Fr   r'   	   \r   N)r'   r0   )lenlstrip)r"   entZquotediZcurcZnextcr   remainr#   r#   r$   _extract_optionst   s"    

z"AuthKeyLineParser._extract_optionsNc             C   s  | j  d  } | j d  s0 | j   d k r: t |  Sd d   } | j   } y | |  \ } } } Wnq t k
 r |  j |  \ }	 }
 | d  k r |	 } y | |
  \ } } } Wn t k
 r t |  SYn XYn Xt | d | d | d | d	 | S)
Nz
# c             S   s   |  j  d  d  } t |  d k  r: t d t |    | d t k r^ t d | d   t |  d k r} | j d  | S)N   zTo few fields: %sr   zInvalid keytype %sr:   )splitr3   	TypeErrorVALID_KEY_TYPESr(   )r5   r*   r#   r#   r$   parse_ssh_key   s    z.AuthKeyLineParser.parse.<locals>.parse_ssh_keyr    r   r   r   )rstrip
startswithstripr   r=   r8   )r"   Zsrc_liner   liner?   r5   r    r   r   Zkeyoptsr7   r#   r#   r$   parse   s"    !
zAuthKeyLineParser.parse)r,   r-   r.   __doc__r8   rD   r#   r#   r#   r$   r/   `   s   r/   c             C   s   g  } t    } g  } x |  D] } yR t j j |  rs t j |  j   } x$ | D] } | j | j |   qS WWq t	 t
 f k
 r t j t d |  Yq Xq W| S)NzError reading lines from %s)r/   ospathisfiler   	load_file
splitlinesr(   rD   IOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerC   r#   r#   r$   parse_authorized_keys   s    	rT   c             C   s   t  d d   | D  } x t d t |    D]k } |  | } | j   sN q/ x? | D]7 } | j | j k rU | } | | k rU | j |  qU W| |  | <q/ Wx | D] } |  j |  q Wd d   |  D } | j d  d j |  S)Nc             S   s"   g  |  ] } | j    r |  q Sr#   )r&   ).0kr#   r#   r$   
<listcomp>   s   	 z*update_authorized_keys.<locals>.<listcomp>r   c             S   s   g  |  ] } t  |   q Sr#   )str)rU   br#   r#   r$   rW      s   	 r:   
)listranger3   r&   r   remover(   r)   )Zold_entrieskeysZto_addr6   r5   rV   keyrP   r#   r#   r$   update_authorized_keys   s     
r`   c             C   sL   t  j |   } | s  | j r0 t d |    t j j | j d  | f S)Nz"Unable to get SSH info for user %rz.ssh)pwdgetpwnampw_dirRuntimeErrorrF   rG   r)   )usernamepw_entr#   r#   r$   users_ssh_info   s    rg   c       	      C   s   d | f d | f d f } |  s' d }  |  j    } g  } xh | D]` } x& | D] \ } } | j | |  } qM W| j d  s t j j | |  } | j |  q@ W| S)Nz%hz%u%%%z%h/.ssh/authorized_keys/)rh   ri   )r<   replacerA   rF   rG   r)   r(   )	valueZhomedirre   ZmacrospathsZrenderedrG   ZmacroZfieldr#   r#   r$   render_authorizedkeysfile_paths   s    rn   c             C   s   t  |   \ } } t j j | d  } g  } t j | d d u y1 t |  } t | j d d  | j	 |   } Wn< t
 t f k
 r | | d <t j t d t | d  Yn XWd  QRX| t |  f S)NZauthorized_keys	recursiveTZauthorizedkeysfilez%h/.ssh/authorized_keysr   zhFailed extracting 'AuthorizedKeysFile' in SSH config from %r, using 'AuthorizedKeysFile' file %r instead)rg   rF   rG   r)   r   SeLinuxGuardparse_ssh_config_maprn   getrc   rK   rL   rM   rN   DEF_SSHD_CFGrT   )re   Zsshd_cfg_filessh_dirrf   Zdefault_authorizedkeys_fileZauth_key_fnsZssh_cfgr#   r#   r$   extract_authorized_keys   s    
ru   c             C   s"  t  |  \ } } t j j |  sP t j | d d t j | | j | j  t	   } g  } x0 |  D]( } | j
 | j t |  d |  qf Wt |  \ } }	 t j | d d b t |	 |  }
 t j t j j |  d d t j | |
 d d t j | | j | j  Wd  QRXd  S)Nmodei  r   ro   Ti  )rg   rF   rG   isdirr   Z
ensure_dirZ	chownbyidZpw_uidZpw_gidr/   r(   rD   rX   ru   rp   r`   dirname
write_file)r^   re   r   rt   pwentrQ   Zkey_entriesrV   Zauth_key_fnZauth_key_entriesZcontentr#   r#   r$   setup_user_keys  s    	&r{   c               @   s@   e  Z d  Z d d d d  Z e d d    Z d d   Z d S)SshdConfigLineNc             C   s   | |  _  | |  _ | |  _ d  S)N)rC   _keyrl   )r"   rC   rV   vr#   r#   r$   r%   )  s    		zSshdConfigLine.__init__c             C   s    |  j  d  k r d  S|  j  j   S)N)r}   lower)r"   r#   r#   r$   r_   .  s    zSshdConfigLine.keyc             C   sS   |  j  d  k r t |  j  St |  j   } |  j rK | d t |  j  7} | Sd  S)Nr'   )r}   rX   rC   rl   )r"   r~   r#   r#   r$   r+   5  s    	zSshdConfigLine.__str__)r,   r-   r.   r%   propertyr_   r+   r#   r#   r#   r$   r|   (  s   r|   c             C   s/   t  j j |   s g  St t j |   j    S)N)rF   rG   rH   parse_ssh_config_linesr   rI   rJ   )rS   r#   r#   r$   parse_ssh_config?  s    r   c             C   s   g  } x |  D] } | j    } | s5 | j d  rK | j t |   q y | j d  d  \ } } Wn* t k
 r | j d d  \ } } Yn X| j t | | |   q W| S)Nr9   r1   =)rB   rA   r(   r|   r<   
ValueError)rP   retrC   r_   valr#   r#   r$   r   E  s    r   c             C   sM   t  |   } | s i  Si  } x* | D]" } | j s5 q# | j | | j <q# W| S)N)r   r_   rl   )rS   rP   r   rC   r#   r#   r$   rq   X  s    	rq   c             C   sg   t  |  } t d | d |   } | rW t j | d j d d   | D  d d d t |  d k S)	zRead fname, and update if changes are necessary.

    @param updates: dictionary of desired values {Option: value}
    @return: boolean indicating if an update was done.rP   updatesrZ   c             S   s   g  |  ] } t  |   q Sr#   )rX   )rU   rC   r#   r#   r$   rW   n  s   	 z%update_ssh_config.<locals>.<listcomp>Zpreserve_modeTr   )r   update_ssh_config_linesr   ry   r)   r3   )r   rS   rP   changedr#   r#   r$   update_ssh_configd  s    	r   c       	      C   st  t    } g  } t d d   | j   D  } x t |  d d D] \ } } | j sY qA | j | k rA | | j } | | } | j |  | j | k r t j d | | |  qA | j	 |  t j d | | | j |  | | _ qA Wt
 |  t
 |  k rpxk | j   D]] \ } } | | k r*q| j	 |  |  j	 t d | |   t j d t
 |   | |  qW| S)	zUpdate the SSH config lines per updates.

    @param lines: array of SshdConfigLine.  This array is updated in place.
    @param updates: dictionary of desired values {Option: value}
    @return: A list of keys in updates that were changed.c             S   s"   g  |  ] } | j    | f  q Sr#   )r   )rU   rV   r#   r#   r$   rW   }  s   	 z+update_ssh_config_lines.<locals>.<listcomp>startr1   z$line %d: option %s already set to %sz#line %d: option %s updated %s -> %sr:   z line %d: option %s added with %s)setdictr^   	enumerater_   addrl   rN   debugr(   r3   itemsr|   )	rP   r   foundr   Zcasemapr6   rC   r_   rl   r#   r#   r$   r   s  s4    		
		r   )r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )rF   ra   Z	cloudinitr   Zloggingr   Z	getLoggerr,   rN   rs   r>   Z_DISABLE_USER_SSH_EXITrX   ZDISABLE_USER_OPTSobjectr   r/   rT   r`   rg   rn   ru   r{   r|   r   r   rq   r   r   r#   r#   r#   r$   <module>	   sV                        U