
    x[hX                        S SK r S SKrS SKrS SKJr  S SKJrJrJr  S SK	J
r
JrJr  \ R                  " \5      rSrSrSrS\" \5      -   S	-   r " S
 S5      r " S S5      rS rS rS rS rS rS r\4S jrS%S jr " S S5      rS\\   4S jr S\\   4S jr!S r"S\S\#4S jr$S r%\4S jr&S  r'\4S!\\\\4      4S" jjr(S# r)S$ r*g)&    N)suppress)ListSequenceTuple)	lifecyclesubputilz/etc/ssh/sshd_config)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-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                   ,    \ rS rSr SS jrS rS rSrg)AuthKeyLineD   Nc                 @    X0l         X@l        XPl        X l        Xl        g N)base64commentoptionskeytypesource)selfr   r   r   r   r   s         4/usr/lib/python3/dist-packages/cloudinit/ssh_util.py__init__AuthKeyLine.__init__E   s         c                 @    U R                   =(       a    U R                  $ r   )r   r   r   s    r   validAuthKeyLine.validN   s    {{+t||+r   c                    / nU R                   (       a  UR                  U R                   5        U R                  (       a  UR                  U R                  5        U R                  (       a  UR                  U R                  5        U R                  (       a  UR                  U R                  5        U(       d  U R
                  $ SR                  U5      $ N )r   appendr   r   r   r   join)r   tokss     r   __str__AuthKeyLine.__str__Q   s~    <<KK%<<KK%;;KK$<<KK%;;88D>!r   )r   r   r   r   r   )NNNN)__name__
__module____qualname____firstlineno__r   r    r(   __static_attributes__ r   r   r   r   D   s    GK,"r   r   c                   (    \ rS rSrSrS rSS jrSrg)AuthKeyLineParsera   a9  
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 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                 L   SnSnU[        U5      :  ax  U(       d  X   S;  ai  X   nUS-   [        U5      :  a  US-   nOMXS-      nUS:X  a  US:X  a  US-   nOUS:X  a  U(       + nUS-   nU[        U5      :  a  U(       a  M_  X   S;  a  Mi  USU nXS R                  5       nXg4$ )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_options"AuthKeyLineParser._extract_optionsu   s     #c(lSV;-F6D1uC EAJEt|E#AA #c(lSV;-F a( R!  r   Nc                    UR                  S5      nUR                  S5      (       d  UR                  5       S:X  a  [        U5      $ S nUR                  5       n U" U5      u  pgn[        UUUUUS9$ ! [         aD    U R                  U5      u  pUc  U	n U" U
5      u  pgn N=! [         a    [        U5      s s $ f = ff = f)Nz
# c                     U R                  S S5      n[        U5      S:  a  [        S[        U5      -  5      eUS   [        ;  a  [        SUS   -  5      e[        U5      S:X  a  UR	                  S5        U$ )N   zTo few fields: %sr   zInvalid keytype %srC   )splitr7   	TypeErrorVALID_KEY_TYPESr%   )r9   r'   s     r   parse_ssh_key.AuthKeyLineParser.parse.<locals>.parse_ssh_key   sp    99T1%D4y1} 3c$i ?@@Awo- 4tAw >?? 4yA~BKr   )r   r   r   r   )rstrip
startswithstripr   rG   r?   )r   src_liner   linerI   r9   r   r   r   keyoptsr>   s              r   parseAuthKeyLineParser.parse   s    v&??34::<2#5x((	 jjl
	-)6s);&Wg 
 	
  	- $ 5 5c :W!--:6-B*' -"8,,-	-s*   A3 3"CB##B=8C<B==Cr/   r   )r*   r+   r,   r-   __doc__r?   rQ   r.   r/   r   r   r1   r1   a   s    &!4(
r   r1   c                    / n[        5       n/ nU  Hw  n [        R                  R                  U5      (       aO  [        R
                  " U5      R                  5       nU H#  nUR                  UR                  U5      5        M%     Mw  My     U$ ! [        [        4 a     [        R                  " [        SU5         M  f = f)NzError reading lines from %s)r1   ospathisfiler	   load_text_file
splitlinesr%   rQ   IOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerO   s         r   parse_authorized_keysrc      s    E FH	Cww~~e$$++E2==?!DOOFLL$67 " %  O ! 	CKK:EB	Cs   A1B,B>=B>c                    [        U Vs/ s H  o"R                  5       (       d  M  UPM     sn5      n[        [        U 5      5       Ha  nX   nUR                  5       (       d  M  U H9  nUR                  UR                  :X  d  M  UnX#;   d  M(  UR                  U5        M;     XPU'   Mc     U H  nU R                  U5        M     U  Vs/ s H  n[        U5      PM     nnUR                  S5        SR                  U5      $ s  snf s  snf )NrC   
)	listr    ranger7   r   remover%   strr&   )	old_entrieskeyskto_addr;   r9   keybr_   s	            r   update_authorized_keysrp      s    d0dggi1d01F3{#$nyy{{Axx3::%;MM!$  A % 3  ))[SV[E) 
LL99U1 1( *s   DD
Dc                     [         R                  " U 5      nU(       a  UR                  (       d  [        SU -  5      e[        R
                  R                  UR                  S5      U4$ )Nz"Unable to get SSH info for user %rz.ssh)pwdgetpwnampw_dirRuntimeErrorrU   rV   r&   )usernamepw_ents     r   users_ssh_inforx      sH    \\(#F?8LMMGGLL/88r   c                 $   SU4SU4S4nU (       d  Sn U R                  5       n/ nU He  nU H  u  pxUR                  Xx5      nM     UR                  S5      (       d  [        R                  R                  X5      nUR                  U5        Mg     U$ )N%h%u)z%%%%h/.ssh/authorized_keys/)rF   replacerL   rU   rV   r&   r%   )	valuehomedirrv   macrospathsrenderedrV   macrofields	            r   render_authorizedkeysfile_pathsr      s     Woh/=F)KKMEH"LE<<-D #s##77<<.D  Or   c                    SnU(       a  Sn[         R                  " U5      nU(       a%  X`:w  a   US:w  a  [        R                  SUUU U5        g[         R                  " U5      nX`:X  a  US-  nO<[         R
                  " U5      n[         R                  " U 5      n	X;   a  US-  nOUS-  nXu-  S	:X  a  [        R                  S
UUU 5        gU(       a"  US-  (       a  [        R                  SUU5        gg)a>  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_ownerr]   debugget_permissions	get_groupget_user_groups)
rv   current_path	full_pathis_filestrictmodesminimal_permissionsownerparent_permissiongroup_owneruser_groupss
             r   check_permissionsr     s	     # NN<(Eu(Uf_		@	
 ,,\:u$nn\2**84%5(  5(.!3		%	
  )E1		@		
 r   c                 2   [        U 5      S   n[        S5      S   n UR                  S5      SS nSn[        R                  R	                  UR
                  5      nU GH  nUSU-   -  n[        R                  R                  U5      (       a  [        R                  SU5          g[        R                  R                  U5      (       a  [        R                  SU5          gUR                  U5      (       d  XcR
                  :X  a  M  [        R                  R                  U5      (       d  [        R                  " U5         S	n	UR                  n
UR                  nUR                  UR
                  5      (       a  S
n	UR                  n
UR                  n[        R                   " XiSS9  [        R"                  " XjU5        S S S 5        [%        XUSU5      nU(       a  GM    g   [        R                  R                  U5      (       d$  [        R                  R'                  U5      (       a  [        R                  SU5        g[        R                  R                  U5      (       dB  [        R(                  " USSSS9  [        R"                  " XR                  UR                  5        [%        XUSU5      nU(       d  g g! , (       d  f       GN= f! [*        [,        4 a.  n[        R.                  " [        [1        U5      5         S nAgS nAff = f)Nr5   r   r~   rC   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)rx   rF   rU   rV   dirnamert   islinkr]   r   rW   rL   existsr	   SeLinuxGuardpw_uidpw_gidmakedirs	chownbyidr   isdir
write_filerZ   r[   r\   ri   )rv   filenamer   
user_pwent
root_pwentdirectoriesparent_folderhome_folder	directoryr   uidgidpermissionses                 r   check_create_pathr   G  st   )!,J'*JGnnS)!B/  ggooj&7&78$IS9_,M ww~~m,,		C! ww~~m,,		@-  &&}55 $5$5577>>-00 &&}5 D$++C$++C$//
0A0ABB$(//(//KK4HNN=s; 6 ,5+K ;U %X 77>>(##rww}}X'>'>II)84 ww~~h'' OOHbuMNN8%6%6
8I8IJ'$
   K 65B W CQ sR   BK ';K #A!K BKK %K 'A K A;K 
K	K L($LLc           
         [        U 5      u  p#[        R                  R                  US5      nUn/ n[        R
                  " USS9    [        U5      nUR                  SS5      nUR                  SS5      n	[        XR                  U 5      nS S S 5        [        WR!                  5       U5       Hb  u  p[#        S
U
;   SU
;   UR%                  SR'                  UR                  5      5      /5      (       d  MH  [)        XW	S:H  5      nU(       d  M`  Un  O   XT:w  a  [        R+                  SU5        U[-        U/5      4$ ! [        [        4 a+    XFS'   [        R                  " [        S	[        US   5         Nf = f! , (       d  f       N= f)Nauthorized_keysT	recursiveauthorizedkeysfiler}   r   yesr   zhFailed extracting 'AuthorizedKeysFile' in SSH config from %r, using 'AuthorizedKeysFile' file %r insteadr{   rz   z{}/zAAuthorizedKeysFile has an user-specific authorized_keys, using %s)rx   rU   rV   r&   r	   r   parse_ssh_config_mapgetr   rt   rZ   r[   r\   r]   DEF_SSHD_CFGziprF   anyrL   formatr   r   rc   )rv   sshd_cfg_filessh_dirrw   default_authorizedkeys_fileuser_authorizedkeys_fileauth_key_fnsssh_cfg	key_pathsr   key_pathauth_key_fnpermissions_oks                r   extract_authorized_keysr     s   &x0W"$'',,w8I"J:L			7d	3	*=9G$&?I "++mU;K:==(L 
40 "%Y__%6!E  &&u||FMM'BC
 
 /{e';N ~+6( "F  >		$	
 	!789 G ! 
	9OKK Q
	 
4	3s+   E=	AD??8E:7E=9E::E==
Fc                 t   [        5       n/ nU  H+  nUR                  UR                  [        U5      US95        M-     [	        U5      u  pg[
        R                  R                  U5      n[        R                  " USS9   [        Xt5      n	[        R                  " XiSS9  S S S 5        g ! , (       d  f       g = f)N)r   Tr   preserve_mode)r1   r%   rQ   ri   r   rU   rV   r   r	   r   rp   r   )
rk   rv   r   r`   key_entriesrl   r   auth_key_entriesr   contents
             r   setup_user_keysr     s     FK6<<A<@A  '>h&G#[ggook*G			7d	3()9GDA 
4	3	3s   ?!B))
B7c                   4    \ rS rSrSS jr\S 5       rS rSrg)SshdConfigLinei  Nc                 (    Xl         X l        X0l        g r   )rO   _keyr   )r   rO   rl   vs       r   r   SshdConfigLine.__init__  s    		
r   c                 R    U R                   c  g U R                   R                  5       $ r   )r   lowerr   s    r   rn   SshdConfigLine.key  s     99yy  r   c                     U R                   c  [        U R                  5      $ [        U R                   5      nU R                  (       a  US[        U R                  5      -   -  nU$ r#   )r   ri   rO   r   )r   r   s     r   r(   SshdConfigLine.__str__  sJ    99tyy>!DIIAzzS3tzz?**Hr   )r   rO   r   )NN)	r*   r+   r,   r-   r   propertyrn   r(   r.   r/   r   r   r   r     s     
 ! !r   r   returnc                     [         R                  R                  U 5      (       d  / $ [        [        R
                  " U 5      R                  5       5      $ r   )rU   rV   rW   parse_ssh_config_linesr	   rX   rY   rb   s    r   parse_ssh_configr     s9    77>>%  	!$"5"5e"<"G"G"IJJr   c                    / nU  H|  nUR                  5       nU(       a  UR                  S5      (       a  UR                  [        U5      5        ML   UR	                  S S5      u  p4UR                  [        X#U5      5        M~     U$ ! [
         a@     UR	                  SS5      u  p4 NB! [
         a    [        R                  SU5          M  f = ff = f)NrB   r5   =z;sshd_config: option "%s" has no key/value pair, skipping it)rM   rL   r%   r   rF   
ValueErrorr]   r   )r_   retrO   rn   vals        r   r   r     s    
 !#Czz|ts++JJ~d+,	zz$*HC 	

>$S12# $ J  		::c1-S 		#
 		s*   B
CB(( CCCCc                     [        U 5      nU(       d  0 $ 0 nU H.  nUR                  (       d  M  UR                  X#R                  '   M0     U$ r   )r   rn   r   )rb   r_   r   rO   s       r   r   r     sC    U#E	
Cxx

HH  Jr   rb   c                     [         R                  R                  U 5      (       d  g[        R                  " U 5      R                  5        H  nUR                  SU  S35      (       d  M    g   g)NFzInclude z	.d/*.confT)rU   rV   rW   r	   rX   rY   rL   )rb   rO   s     r   _includes_dconfr   "  sV    77>>%  ##E*557??XeWI677 8 r   c                 `   [        U 5      (       a  [        R                  R                  U  S35      (       d  [        R
                  " U  S3SS9  [        R                  R                  U  S3S5      n [        R                  R                  U 5      (       d  [        R                  " U S5        U $ )Nz.dr   )r   z50-cloud-init.confr   )	r   rU   rV   r   r	   
ensure_dirr&   rW   ensure_filer   s    r   "_ensure_cloud_init_ssh_config_filer   +  s}    uww}}wb\**OOugRLu5wb\+?@ww~~e$$UE*Lr   c                     [        U5      n[        U5      n[        X S9nU(       aB  [        R                  " USR                  U Vs/ s H  n[        U5      PM     sn5      S-   SS9  [        U5      S:g  $ s  snf )zRead fname, and update if changes are necessary.

@param updates: dictionary of desired values {Option: value}
@return: boolean indicating if an update was done.)r_   updatesre   Tr   r   )r   r   update_ssh_config_linesr	   r   r&   ri   r7   )r   rb   r_   changedrO   s        r   update_ssh_configr   6  sq    
 /u5EU#E%ECGIIU3UTs4yU34t;	

 w<1 4s   A7c                    [        5       n/ n[        UR                  5        Vs/ s H  oDR                  5       U4PM     sn5      n[	        U SS9 H  u  pgUR
                  (       d  M  UR
                  U;   d  M*  XWR
                     nX   n	UR                  U5        UR                  U	:X  a  [        R                  SXhU	5        Mv  UR                  U5        [        R                  SUUUR                  U	5        Xl        M     [        U5      [        U5      :w  al  UR                  5        HX  u  pX;   a  M  UR                  U5        U R                  [        SX5      5        [        R                  S[        U 5      X5        MZ     U$ s  snf )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.r5   )startz$line %d: option %s already set to %sz#line %d: option %s updated %s -> %srC   z line %d: option %s added with %s)setdictrk   r   	enumeratern   addr   r]   r   r%   r7   itemsr   )
r_   r   foundr   rl   casemapr;   rO   rn   r   s
             r   r   r   G  sB    EEG GLLN;NqWWYNN;<GU!,xx88w((#CLEIIcNzzU"		:AE s#		9JJ #
) -, 5zS\!!--/JC|NN3LLC78II2CJ * NC <s   F
r_   c                     U (       d  g [        U5      nS U  5       n[        R                  " USR                  U5      S-   SSS9  g )Nc              3   4   #    U  H  u  pU S U 3v   M     g7f)r$   Nr/   ).0rl   r   s      r   	<genexpr>$append_ssh_config.<locals>.<genexpr>y  s     ,eda!AaSzes   re   abT)omoder   )r   r	   r   r&   )r_   rb   r   s      r   append_ssh_configr
  u  sB    .u5E,e,GOO		'T!	r   c                  B   Sn [        [        R                  5         [        R                  " SS/SS/S9u  pSSS5        SnU R                  S	5       H8  nUR	                  U5      (       d  M  U[        U5      UR                  S
5       s  $    g! , (       d  f       N^= f)zGet the full version of the OpenSSH sshd daemon on the system.

On an ubuntu system, this would look something like:
1.2p1 Ubuntu-1ubuntu0.1

If we can't find `sshd` or parse the version number, return None.
rC   sshdz-Vr   r5   )rcsNOpenSSH_re   ,)r   r   ProcessExecutionErrorrF   rL   r7   find)err_prefixrO   s       r   get_opensshd_versionr    s     C	$,,	-FD>1v6 
.F		$??6""Fdiin55    
.	-s   B
Bc                  j   Sn [        5       nUc  [        R                  R                  U 5      $ SU;   a  USUR	                  S5       n OSU;   a  USUR	                  S5       n OUn  [        R                  R                  U 5      n U $ ! [
        [        4 a    [        R                  SU 5         gf = f)zGet the upstream version of the OpenSSH sshd daemon on the system.

This will NOT include the portable number, so if the Ubuntu version looks
like `1.2p1 Ubuntu-1ubuntu0.1`, then this function would return
`1.2`
z9.0Npr$   z Could not parse sshd version: %s)	r  r   Versionfrom_strr  r   rG   r]   warning)upstream_versionfull_versions     r   get_opensshd_upstream_versionr    s     ')L  ))*:;;
l'(@,*;*;C*@A		'(@,*;*;C*@A'J$,,556FG	" J68HIJs   ( B	 	&B21B2r   )+loggingrU   rr   
contextlibr   typingr   r   r   	cloudinitr   r   r	   	getLoggerr*   r]   r   rH   _DISABLE_USER_SSH_EXITri   DISABLE_USER_OPTSr   r1   rc   rp   rx   r   r   r   r   r   r   r   r   r   boolr   r   r   r   r
  r  r  r/   r   r   <module>r&     s9    	 
  ( ( + +! & ,   ()* -00 " ":V
 V
r 89*BJL^ 5A 6rB .KtN3 KT.%9 6	3 4  &2 "+\ ?K 
XeCHo6 
(Jr   