
    ܍~cP                     2   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          z   dz   Z G d	 d
          Z G d d          Zd Zd Zd Zd Zd Zd Ze	fdZddZ G d d          Zd Zd Zd ZdedefdZe	fdZd ZdS )     N)log)utilz/etc/ssh/sshd_config)dsarsaecdsaed25519z(ecdsa-sha2-nistp256-cert-v01@openssh.comzecdsa-sha2-nistp256z(ecdsa-sha2-nistp384-cert-v01@openssh.comzecdsa-sha2-nistp384z(ecdsa-sha2-nistp521-cert-v01@openssh.comzecdsa-sha2-nistp521z+sk-ecdsa-sha2-nistp256-cert-v01@openssh.comz"sk-ecdsa-sha2-nistp256@openssh.comz#sk-ssh-ed25519-cert-v01@openssh.comzsk-ssh-ed25519@openssh.comzssh-dss-cert-v01@openssh.comzssh-dssz ssh-ed25519-cert-v01@openssh.comzssh-ed25519zssh-rsa-cert-v01@openssh.comzssh-rsazssh-xmss-cert-v01@openssh.comz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                   $    e Zd Z	 ddZd Zd ZdS )AuthKeyLineNc                 L    || _         || _        || _        || _        || _        d S N)base64commentoptionskeytypesource)selfr   r   r   r   r   s         4/usr/lib/python3/dist-packages/cloudinit/ssh_util.py__init__zAuthKeyLine.__init__F   s+         c                     | j         o| j        S r   )r   r   r   s    r   validzAuthKeyLine.validO   s    {+t|+r   c                 J   g }| j         r|                    | j                    | j        r|                    | j                   | j        r|                    | j                   | j        r|                    | j                   |s| j        S d                    |          S N )r   appendr   r   r   r   join)r   tokss     r   __str__zAuthKeyLine.__str__R   s    < 	&KK%%%< 	&KK%%%; 	%KK$$$< 	&KK%%% 	";88D>>!r   )NNNN)__name__
__module____qualname__r   r   r!    r   r   r   r   E   sI        GK   , , ," " " " "r   r   c                        e Zd ZdZd Z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                 x   d}d}|t          |          k     rz|s
||         dvrn||         }|dz   t          |          k    r|dz   }nJ||dz            }|dk    r|dk    r|dz   }n	|dk    r| }|dz   }|t          |          k     r|d||         dvn|d|         }||d                                         }||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)lenlstrip)r   entquotedicurcnextcr   remains           r   _extract_optionsz"AuthKeyLineParser._extract_optionsv   s     #c((lllSV;-F-Fq6D1uC  EAJEt||E#AA #c((lllSV;-F-F ac( QRR!!  r   Nc                    |                     d          }|                    d          s|                                dk    rt          |          S d }|                                }	  ||          \  }}}n^# t          $ rQ |                     |          \  }	}
||	}	  ||
          \  }}}n!# t          $ r t          |          cY cY S w xY wY nw xY wt          |||||          S )Nz
# c                 4   |                      d d          }t          |          dk     rt          dt          |          z            |d         t          vrt          d|d         z            t          |          dk    r|                    d           |S )N   zTo few fields: %sr   zInvalid keytype %sr7   )splitr,   	TypeErrorVALID_KEY_TYPESr   )r.   r    s     r   parse_ssh_keyz.AuthKeyLineParser.parse.<locals>.parse_ssh_key   s    99T1%%D4yy1}} 3c$ii ?@@@Awo-- 4tAw >??? 4yyA~~BKr   )r   r   r   r   )rstrip
startswithstripr   r;   r4   )r   src_liner   liner=   r.   r   r   r   keyoptsr3   s              r   parsezAuthKeyLineParser.parse   s@   v&&??3 	)4::<<2#5#5x(((	 	 	 jjll
	-)6s););&Wfgg 	- 	- 	- $ 5 5c : :Wf!--:]6-B-B*&'' - - -"8,,,,,,,- #*'	- 
 
 
 	
s6   *A: :&C!B10C1C
CCCCr   )r"   r#   r$   __doc__r4   rD   r%   r   r   r'   r'   b   sA         &! ! !4(
 (
 (
 (
 (
 (
r   r'   c                 ~   g }t                      }g }| D ]}	 t          j                            |          rSt	          j        |                                          }|D ]*}|                    |                    |                     +v# t          t          f$ r t	          j        t          d|           Y w xY w|S )NzError reading lines from %s)r'   ospathisfiler   	load_file
splitlinesr   rD   IOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerB   s         r   parse_authorized_keysrU      s    E  FH C C	Cw~~e$$ 8u--88::! 8 8DOOFLL$6$67777! 	C 	C 	CK:EBBBBB	C Os   A2B,B:9B:c                    t          d |D                       }t          dt          |                     D ]T}| |         }|                                s|D ]-}|j        |j        k    r|}||v r|                    |           .|| |<   U|D ]}|                     |           d | D             }|                    d           d                    |          S )Nc                 :    g | ]}|                                 |S r%   )r   .0ks     r   
<listcomp>z*update_authorized_keys.<locals>.<listcomp>   s%    000aggii01000r   r   c                 ,    g | ]}t          |          S r%   str)rY   bs     r   r[   z*update_authorized_keys.<locals>.<listcomp>   s    )))SVV)))r   r7   
)listranger,   r   r   remover   r   )old_entrieskeysto_addr0   r.   rZ   keyrQ   s           r   update_authorized_keysrh      s   00d00011F1c+&&''  !nyy{{ 	 	% 	%Ax3:%%;;MM!$$$A     3 *)[)))E 
LL99Ur   c                     t          j        |           }|r|j        st          d| z            t          j                            |j        d          |fS )Nz"Unable to get SSH info for user %rz.ssh)pwdgetpwnampw_dirRuntimeErrorrG   rH   r   )usernamepw_ents     r   users_ssh_inforp      sU    \(##F N N?8LMMMGLL//88r   c                 &   d|fd|fdf}| sd} |                                  }g }|D ]j}|D ]\  }}|                    ||          }|                    d          s t          j                            ||          }|                    |           k|S )N%h%u)z%%%%h/.ssh/authorized_keys/)r:   replacer?   rG   rH   r   r   )	valuehomedirrn   macrospathsrenderedrH   macrofields	            r   render_authorizedkeysfile_pathsr      s     Woh/=F *)KKMMEH  " 	. 	.LE5<<u--DDs## 	/7<<..DOr   c                    d}|rd}t          j        |          }|r,|| k    r&|dk    r t                              d||| |           dS t          j        |          }|| k    r|dz  }n7t          j        |          }t          j        |           }	||	v r|dz  }n|dz  }||z  d	k    rt                              d
|||            dS |r'|dz  d	k    rt                              d||           dS dS )aV  Check if the file/folder in @current_path has the right permissions.

    We need to check that:
    1. If StrictMode is enabled, the owner is either root or the user
    2. the user can access the file/folder, otherwise ssh won't use it
    3. If StrictMode is enabled, no write permission is given to group
       and world users (022)
    i  i  rootzXPath %s in %s must be own by user %s or by root, but instead is own by %s. Ignoring key.F  8      r   zBPath %s in %s must be accessible by user %s, check its permissions   zRPath %s in %s must not give writepermission to group or world users. Ignoring key.T)r   	get_ownerrO   debugget_permissions	get_groupget_user_groups)
rn   current_path	full_pathis_filestrictmodesminimal_permissionsownerparent_permissiongroup_owneruser_groupss
             r   check_permissionsr     se      $# N<((E 	u((Uf__		@	
 	
 	
 u,\::u$n\22*844+%%5(  5(..!33		%	
 	
 	
 u  (50A55		@		
 	
 	
 u4r   c                    t          |           d         }t          d          d         }	 |                    d          dd         }d}t          j                            |j                  }|D ]p}|d|z   z  }t          j                            |          rt                              d|            dS t          j        	                    |          rt                              d|            dS |
                    |          s||j        k    rt          j                            |          st          j        |          5  d	}	|j        }
|j        }|
                    |j                  rd
}	|j        }
|j        }t          j        ||	d           t          j        ||
|           d d d            n# 1 swxY w Y   t%          | ||d|          }|s dS rt          j                            |          st          j                            |          rt                              d|           dS t          j                            |          s8t          j        |ddd           t          j        ||j        |j                   t%          | ||d|          }|sdS nF# t*          t,          f$ r2}t          j        t          t1          |                     Y d }~dS d }~ww xY wdS )Nr*   r   rv   r7   z-Invalid directory. Symlink exists in path: %sFz*Invalid directory. File exists in path: %s  r   T)modeexist_okz%s is not a file!  )r   ensure_dir_exists)rp   r:   rG   rH   dirnamerl   islinkrO   r   rI   r?   existsr   SeLinuxGuardpw_uidpw_gidmakedirs	chownbyidr   isdir
write_filerL   rM   rN   r^   )rn   filenamer   
user_pwent
root_pwentdirectoriesparent_folderhome_folder	directoryr   uidgidpermissionses                 r   check_create_pathr   H  sS   ))!,J''*JGnnS))!B$/  gooj&788$ *	 *	IS9_,M w~~m,, 		C!   uuw~~m,, 		@-   uu &&}55 J$5557>>-00 < &}55 	< 	< D$+C$+C$//
0ABB 0$(/(/KD4HHHHN=#s;;;	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< ,-5+ K  uu 7>>(## 	rw}}X'>'> 	II)84445 w~~h'' 	K OHbuMMMMN8Z%6
8IJJJ'h$
 
  	5	W   CQ   uuuuu 4sX   BJ- 9;J- 6AJ- 
A(F>2J- >G	J- G	J- !AJ- >A,J- -K0>'K++K0c           
      d   t          |           \  }}t          j                            |d          }|}g }t	          j        |d          5  	 t          |          }|                    dd          }|                    dd          }	t          ||j	        |           }nC# t          t          f$ r/ ||d<   t	          j        t          d	t          |d                    Y nw xY wd d d            n# 1 swxY w Y   t          |                                |          D ]a\  }
}t#          d
|
v d|
v |                    d                    |j	                            g          rt)          | ||	dk              }|r|} nb||k    rt                              d|           |t-          |g          fS )Nauthorized_keysT	recursiveauthorizedkeysfileru   r   yesr   zhFailed extracting 'AuthorizedKeysFile' in SSH config from %r, using 'AuthorizedKeysFile' file %r insteadrs   rr   z{}/zAAuthorizedKeysFile has an user-specific authorized_keys, using %s)rp   rG   rH   r   r   r   parse_ssh_config_mapgetr   rl   rL   rM   rN   rO   DEF_SSHD_CFGzipr:   anyr?   formatr   r   rU   )rn   sshd_cfg_filessh_dirro   default_authorizedkeys_fileuser_authorizedkeys_fileauth_key_fnsssh_cfg	key_pathsr   key_pathauth_key_fnpermissions_oks                r   extract_authorized_keysr     sC   &x00Wf"$',,w8I"J"J:L		7d	3	3	3  	*=99G$&? I "++mU;;K:6=( LL ! 
	 
	 
	9LOK Q    
	              0 "%Y__%6%6!E!E  +  &&u||FM'B'BCC
 
 	 /+{e'; N  +6(#>>>		$	
 	
 	
 	!7899 s7   C0AB! C0!=C!C0 C!!C00C47C4c                    t                      }g }| D ]9}|                    |                    t          |          |                     :t	          |          \  }}t
          j                            |          }t          j	        |d          5  t          ||          }	t          j        ||	d           d d d            d S # 1 swxY w Y   d S )N)r   Tr   preserve_mode)r'   r   rD   r^   r   rG   rH   r   r   r   rh   r   )
re   rn   r   rR   key_entriesrZ   r   auth_key_entriesr   contents
             r   setup_user_keysr     s-     FK B B6<<A<@@AAAA '>h&G&G#["gook**G		7d	3	3	3 B B()9;GGWDAAAAB B B B B B B B B B B B B B B B B Bs   (C		CCc                   2    e Zd ZddZed             Zd ZdS )SshdConfigLineNc                 0    || _         || _        || _        d S r   )rB   _keyrx   )r   rB   rZ   vs       r   r   zSshdConfigLine.__init__  s    		


r   c                 F    | j         d S | j                                         S r   )r   lowerr   s    r   rg   zSshdConfigLine.key  s!    94y   r   c                     | j         t          | j                  S t          | j                   }| j        r|dt          | j                  z   z  }|S r   )r   r^   rB   rx   )r   r   s     r   r!   zSshdConfigLine.__str__  sK    9ty>>!DIAz +S3tz??**Hr   )NN)r"   r#   r$   r   propertyrg   r!   r%   r   r   r   r     sR           
 ! ! X!    r   r   c                     t           j                            |           sg S t          t	          j        |                                                     S r   )rG   rH   rI   parse_ssh_config_linesr   rJ   rK   )rT   s    r   parse_ssh_configr     sA    7>>%   	!$."7"7"B"B"D"DEEEr   c                    g }| D ]}|                                 }|r|                    d          r#|                    t          |                     P	 |                    d d          \  }}nW# t
          $ rJ 	 |                    dd          \  }}n,# t
          $ r t                              d|           Y Y w xY wY nw xY w|                    t          |||                     |S )Nr6   r*   =z;sshd_config: option "%s" has no key/value pair, skipping it)r@   r?   r   r   r:   
ValueErrorrO   r   )rQ   retrB   rg   vals        r   r   r     s%   
 C 3 3zz|| 	ts++ 	JJ~d++,,,	zz$**HC 		 		 		::c1--SS   		#  
  S		 	

>$S112222Js6   A00
C;BC%B>:C=B>>CCc                 h    t          |           }|si S i }|D ]}|j        s
|j        ||j        <   |S r   )r   rg   rx   )rT   rQ   r   rB   s       r   r   r     sQ    U##E 	
C # #x 	
DHJr   rT   returnc                     t           j                            |           sdS t          | d          5 }|D ])}|                    d|  d          r d d d            dS *	 d d d            n# 1 swxY w Y   dS )NFrzInclude z	.d/*.confT)rG   rH   rI   openr?   )rT   frB   s      r   _includes_dconfr   #  s    7>>%   u	eS		 Q 	 	D:%:::;;        	               5s   A,A,,A03A0c                    t          |          rt          j                            | d          st	          j        | dd           t          j                            | dd          }t          j                            |          st	          j        |d           t          |          }t          ||           }|r7t	          j        |d                    d |D                       dz   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.z.dr   )r   z50-cloud-init.confr   )rQ   updatesr`   c                 ,    g | ]}t          |          S r%   r]   )rY   rB   s     r   r[   z%update_ssh_config.<locals>.<listcomp>>  s    333Ts4yy333r   Tr   r   )r   rG   rH   r   r   
ensure_dirr   rI   ensure_filer   update_ssh_config_linesr   r,   )r   rT   rQ   changeds       r   update_ssh_configr   -  s   
 u +w}}\\\** 	6OuLLLu5555\\\+?@@w~~e$$ 	+UE***U##E%E7CCCG 
II33U33344t;	
 	
 	
 	

 w<<1r   c                 4   t                      }g }t          d |                                D                       }t          | d          D ]\  }}|j        s|j        |v r||j                 }||         }|                    |           |j        |k    rt                              d|||           i|	                    |           t                              d|||j        |           ||_        t          |          t          |          k    r|                                D ]m\  }}||v r
|	                    |           | 	                    t          d||                     t                              dt          |           ||           n|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                 :    g | ]}|                                 |fS r%   )r   rX   s     r   r[   z+update_ssh_config_lines.<locals>.<listcomp>N  s$    ;;;qQWWYYN;;;r   r*   )startz$line %d: option %s already set to %sz#line %d: option %s updated %s -> %sr7   z line %d: option %s added with %s)setdictre   	enumeraterg   addrx   rO   r   r   r,   itemsr   )	rQ   r   foundr   casemapr0   rB   rg   rx   s	            r   r   r   D  s    EEEG ;;GLLNN;;;<<GuA... # #	Dx 	8w$(#CCLEIIcNNNzU""		:AsE    s###		9J   #

5zzS\\!!!--// 	 	JCe||NN3LLC77888II2CJJU    Nr   r   ) rG   rj   	cloudinitr   loggingr   	getLoggerr"   rO   r   r<   _DISABLE_USER_SSH_EXITr^   DISABLE_USER_OPTSr   r'   rU   rh   rp   r   r   r   r   r   r   r   r   r   boolr   r   r   r%   r   r   <module>r      s(   
			 



 $ $ $ $ $ $      g!! & 2   c())* -00 " " " " " " " ":V
 V
 V
 V
 V
 V
 V
 V
r     89 9 9  *B B BJL L L^ 5A 6 6 6 6rB B B B       .F F F  6	 	 	3 4     &2    .+ + + + +r   