
    }fX                        d dl Z d dlZd dlZd dlmZ d dlmZmZmZ d dl	m
Z
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ee   fdZdee   fdZ d Z!dede"fdZ#d Z$efdZ%d  Z&efd!eeeef      fd"Z'd# Z(d$ Z)y)&    N)suppress)ListSequenceTuple)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                   "    e Zd Z	 ddZd Zd Zy)AuthKeyLineNc                 J    || _         || _        || _        || _        || _        y 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__E   s'         c                 6    | j                   xr | j                  S r   )r   r   r   s    r   validzAuthKeyLine.validN   s    {{+t||+r   c                 |   g }| j                   r|j                  | j                          | j                  r|j                  | j                         | j                  r|j                  | j                         | j                  r|j                  | j                         |s| j
                  S dj                  |      S N )r   appendr   r   r   r   join)r   tokss     r   __str__zAuthKeyLine.__str__Q   s~    <<KK%<<KK%;;KK$<<KK%;;88D>!r   )NNNN)__name__
__module____qualname__r   r   r$    r   r   r   r   D   s    GK,"r   r   c                       e Zd ZdZd ZddZy)AuthKeyLineParserau  
    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                 $   d}d}|t        |      k  rc|s||   dvrZ||   }|dz   t        |      k\  r|dz   }n>||dz      }|dk(  r|dk(  r|dz   }n|dk(  r| }|dz   }|t        |      k  r|rR||   dvrZ|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)lenlstrip)r   entquotedicurcnextcr   remains           r   _extract_optionsz"AuthKeyLineParser._extract_optionsu   s     #c(lSV;-Fq6D1uC EAJEt|E#AA #c(lSV;-F a( QR!  r   Nc                    |j                  d      }|j                  d      s|j                         dk(  rt        |      S d }|j                         }	  ||      \  }}}t        |||||      S # t        $ rE | j                  |      \  }	}
||	}	  ||
      \  }}}n# t        $ r t        |      cY cY S w xY wY ]w xY w)Nz
# c                     | j                  d d      }t        |      dk  rt        dt        |      z        |d   t        vrt        d|d   z        t        |      dk(  r|j	                  d       |S )N   zTo few fields: %sr   zInvalid keytype %sr:   )splitr/   	TypeErrorVALID_KEY_TYPESr!   )r1   r#   s     r   parse_ssh_keyz.AuthKeyLineParser.parse.<locals>.parse_ssh_key   sp    99T1%D4y1} 3c$i ?@@Awo- 4tAw >?? 4yA~BKr   )r   r   r   r   )rstrip
startswithstripr   r>   r7   )r   src_liner   liner@   r1   r   r   r   keyoptsr6   s              r   parsezAuthKeyLineParser.parse   s    v&??34::<2#5x((	 jjl
	-)6s);&Wfg 
 	
  	- $ 5 5c :Wf!--:6-B*&' -"8,,- #*	-s6   A1 1!B?B B? B94B?8B99B?>B?r   )r%   r&   r'   __doc__r7   rG   r(   r   r   r*   r*   a   s    &!4(
r   r*   c                 d   g }t               }g }| D ]l  }	 t        j                  j                  |      rJt	        j
                  |      j                         }|D ]"  }|j                  |j                  |             $ n |S # t        t        f$ r t	        j                  t        d|       Y w xY w)NzError reading lines from %s)r*   ospathisfiler   load_text_file
splitlinesr!   rG   IOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerE   s         r   parse_authorized_keysrX      s    E FH C	Cww~~e$++E2==?! 8DOOFLL$678	C O ! 	CKK:EB	Cs   A)B*B/.B/c                    t        |D cg c]  }|j                         s| c}      }t        t        |             D ]V  }| |   }|j                         s|D ]4  }|j                  |j                  k(  s|}||v s$|j                  |       6 || |<   X |D ]  }| j                  |        | D cg c]  }t        |       }}|j                  d       dj                  |      S c c}w c c}w )Nr:   
)	listr   ranger/   r   remover!   strr"   )	old_entrieskeyskto_addr3   r1   keybrT   s	            r   update_authorized_keysre      s    d0aggi101F3{#$ !nyy{ 	%Axx3::%;MM!$	% A   3  ))SV)E) 
LL99U1 1( *s   C*C*4C/c                     t        j                  |       }|r|j                  st        d| z        t        j
                  j                  |j                  d      |fS )Nz"Unable to get SSH info for user %rz.ssh)pwdgetpwnampw_dirRuntimeErrorrJ   rK   r"   )usernamepw_ents     r   users_ssh_inform      sH    \\(#F?8LMMGGLL/88r   c                    d|fd|fdf}| sd} | j                         }g }|D ]`  }|D ]  \  }}|j                  ||      } |j                  d      s t        j                  j                  ||      }|j                  |       b |S )N%h%u)z%%%%h/.ssh/authorized_keys/)r=   replacerB   rJ   rK   r"   r!   )	valuehomedirrk   macrospathsrenderedrK   macrofields	            r   render_authorizedkeysfile_pathsr|      s     Woh/=F)KKMEH " 	.LE5<<u-D	.s#77<<.D Or   c                    d}|rd}t        j                  |      }|r$|| k7  r|dk7  rt        j                  d||| |       yt        j                  |      }|| k(  r|dz  }n9t        j
                  |      }t        j                  |       }	||	v r|dz  }n|dz  }||z  d	k(  rt        j                  d
|||        y|r |dz  d	k7  rt        j                  d||       yy)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_ownerrR   debugget_permissions	get_groupget_user_groups)
rk   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		%	
  (50A5		@		
 r   c                    t        |       d   }t        d      d   }	 |j                  d      dd }d}t        j                  j	                  |j
                        }|D ]h  }|d|z   z  }t        j                  j                  |      rt        j                  d|        yt        j                  j                  |      rt        j                  d|        y|j                  |      s||j
                  k(  rt        j                  j                  |      st        j                  |      5  d	}	|j                  }
|j                  }|j                  |j
                        rd
}	|j                  }
|j                  }t        j                   ||	d       t        j"                  ||
|       d d d        t%        | ||d|      }|ri y t        j                  j                  |      st        j                  j'                  |      rt        j                  d|       yt        j                  j                  |      sDt        j(                  |ddd       t        j"                  ||j                  |j                         t%        | ||d|      }|sy	 y# 1 sw Y   xY w# t*        t,        f$ r-}t        j.                  t        t1        |             Y d }~yd }~ww xY w)Nr-   r~   rs   r:   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)rm   r=   rJ   rK   dirnameri   islinkrR   r   rL   rB   existsr   SeLinuxGuardpw_uidpw_gidmakedirs	chownbyidr   isdir
write_filerO   rP   rQ   r^   )rk   filenamer   
user_pwent
root_pwentdirectoriesparent_folderhome_folder	directoryr   uidgidpermissionses                 r   check_create_pathr   G  sr   )!,J'*JGnnS)!B/  ggooj&7&78$ *	IS9_,M ww~~m,		C! ww~~m,		@-  &&}5 J$5$5577>>-0 &&}5 	< D$++C$++C$//
0A0AB$(//(//KKD4HNN=#s;	< ,-5+K U*	X 77>>(#rww}}X'>II)84 ww~~h' OOHbuMNN8Z%6%6
8I8IJ'h$
   K	< 	<B W CQ sR   BJ# "6J# AJ# .A?J-J# J# 
AJ#  A4J# J 	J# #K2#KKc           
         t        |       \  }}t        j                  j                  |d      }|}g }t	        j
                  |d      5  	 t        |      }|j                  dd      }|j                  dd      }	t        ||j                  |       }d d d        t        j!                         |      D ]V  \  }
}t#        d
|
v d|
v |j%                  dj'                  |j                              g      sAt)        | |	dk(        }|sT|} n ||k7  rt        j+                  d|       |t-        |g      fS # t        t        f$ r+ ||d<   t	        j                  t        d	t        |d          Y w xY w# 1 sw Y   xY w)Nauthorized_keysT	recursiveauthorizedkeysfilerr   r   yesr   zhFailed extracting 'AuthorizedKeysFile' in SSH config from %r, using 'AuthorizedKeysFile' file %r insteadrp   ro   z{}/zAAuthorizedKeysFile has an user-specific authorized_keys, using %s)rm   rJ   rK   r"   r   r   parse_ssh_config_mapgetr|   ri   rO   rP   rQ   rR   DEF_SSHD_CFGzipr=   anyrB   formatr   r   rX   )rk   sshd_cfg_filessh_dirrl   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Wf"$'',,w8I"J:L			7d	3 	*=9G$&?I "++mU;K:6==(L0 "%Y__%6!E +  &&u||FMM'BC
 /+{e';N +6(  #>>		$	
 	!789 G ! 
	9LOKK Q
	 s+   
E3AD667E0-E3/E00E33E<c                 z   t               }g }| D ]-  }|j                  |j                  t        |      |             / t	        |      \  }}t
        j                  j                  |      }t        j                  |d      5  t        ||      }	t        j                  ||	d       d d d        y # 1 sw Y   y xY w)N)r   Tr   preserve_mode)r*   r!   rG   r^   r   rJ   rK   r   r   r   re   r   )
r`   rk   r   rU   key_entriesra   r   auth_key_entriesr   contents
             r   setup_user_keysr     s     FK B6<<A<@AB '>h&G#["ggook*G			7d	3 B()9;GWDAB B Bs   %B11B:c                   *    e Zd ZddZed        Zd Zy)SshdConfigLineNc                 .    || _         || _        || _        y r   )rE   _keyru   )r   rE   ra   vs       r   r   zSshdConfigLine.__init__  s    		
r   c                 P    | j                   y | j                   j                         S r   )r   lowerr   s    r   rc   zSshdConfigLine.key  s     99yy  r   c                     | j                   t        | j                        S t        | j                         }| j                  r|dt        | j                        z   z  }|S r   )r   r^   rE   ru   )r   r   s     r   r$   zSshdConfigLine.__str__  sJ    99tyy>!DIIAzzS3tzz?**Hr   )NN)r%   r&   r'   r   propertyrc   r$   r(   r   r   r   r     s     
 ! !r   r   returnc                     t         j                  j                  |       sg S t        t	        j
                  |       j                               S r   )rJ   rK   rL   parse_ssh_config_linesr   rM   rN   rW   s    r   parse_ssh_configr     s6    77>>% 	!$"5"5e"<"G"G"IJJr   c                    g }| D ]r  }|j                         }|r|j                  d      r|j                  t        |             A	 |j	                  d d      \  }}|j                  t        |||             t |S # t
        $ r@ 	 |j	                  dd      \  }}n&# t
        $ r t        j                  d|       Y Y w xY wY hw xY w)Nr9   r-   =z;sshd_config: option "%s" has no key/value pair, skipping it)rC   rB   r!   r   r=   
ValueErrorrR   r   )rT   retrE   rc   vals        r   r   r     s    
 !#C 3zz|ts+JJ~d+,	zz$*HC 	

>$S12#3$ J  		::c1-S 		#
  		s6   A<<	CBCB?;C>B??CCc                     t        |       }|si S i }|D ](  }|j                  s|j                  ||j                  <   * |S r   )r   rc   ru   )rW   rT   r   rE   s       r   r   r     sJ    U#E	
C #xx

DHH# Jr   rW   c                     t         j                  j                  |       syt        | d      5 }|D ]!  }|j	                  d|  d      s d d d        y 	 d d d        y# 1 sw Y   yxY w)NFrzInclude z	.d/*.confT)rJ   rK   rL   openrB   )rW   frE   s      r   _includes_dconfr   "  sl    77>>% 	eS	 Q 	D%	:; 	 	 s   A	AAA'c                 D   t        |       rt        j                  j                  |  d      st	        j
                  |  dd       t        j                  j                  |  dd      } t        j                  j                  |       st	        j                  | d       | S )Nz.dr   )r   z50-cloud-init.confr   )	r   rJ   rK   r   r   
ensure_dirr"   rL   ensure_filer   s    r   "_ensure_cloud_init_ssh_config_filer   ,  st    uww}}wb\*OOugRLu5wb\+?@ww~~e$UE*Lr   c                     t        |      }t        |      }t        ||       }|rAt        j                  |dj                  |D cg c]  }t        |       c}      dz   d       t        |      dk7  S c c}w )zRead fname, and update if changes are necessary.

    @param updates: dictionary of desired values {Option: value}
    @return: boolean indicating if an update was done.)rT   updatesrZ   Tr   r   )r   r   update_ssh_config_linesr   r   r"   r^   r/   )r   rW   rT   changedrE   s        r   update_ssh_configr   7  so    
 /u5EU#E%E7CGIIU3Ts4y34t;	

 w<1 4s   A5c                    t               }g }t        |j                         D cg c]  }|j                         |f c}      }t	        | d      D ]  \  }}|j
                  s|j
                  |v s"||j
                     }||   }	|j                  |       |j                  |	k(  rt        j                  d|||	       o|j                  |       t        j                  d|||j                  |	       |	|_         t        |      t        |      k7  rk|j                         D ]X  \  }}	||v r|j                  |       | j                  t        d||	             t        j                  dt        |       ||	       Z |S c c}w )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.r-   )startz$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`   r   	enumeraterc   addru   rR   r   r!   r/   itemsr   )
rT   r   foundr   ra   casemapr3   rE   rc   ru   s
             r   r   r   H  s\    EEG GLLN;qQWWYN;<GuA. #	Dxx88w$((#CCLEIIcNzzU"		:AsE s#		9JJ #
)#, 5zS\!!--/ 	JCe|NN3LLC78II2CJU	 NC <s   FrT   c                     | sy t        |      }d | D        }t        j                  |dj                  |      dz   dd       y )Nc              3   0   K   | ]  \  }}| d |   yw)r    Nr(   ).0ra   r   s      r   	<genexpr>z$append_ssh_config.<locals>.<genexpr>z  s     ,da!AaSz,s   rZ   abT)omoder   )r   r   r   r"   )rT   rW   r   s      r   append_ssh_configr   v  sB    .u5E,e,GOO		'T!	r   c                  0   d} t        t        j                        5  t        j                  ddgddg      \  }} ddd       d}| j                  d	      D ]2  }|j	                  |      s|t        |      |j                  d
       c S  y# 1 sw Y   RxY w)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.
    r:   sshdz-Vr   r-   )rcsNOpenSSH_rZ   ,)r   r   ProcessExecutionErrorr=   rB   r/   find)err_prefixrE   s       r   get_opensshd_versionr	    s     C	$,,	- 7FD>1v637F		$ 6??6"Fdiin556 7 7s   BBc                  ^   d} t               }|t        j                  j                  |       S d|v r|d|j	                  d       } nd|v r|d|j	                  d       } n|} 	 t        j                  j                  |       } | S # t
        t        f$ r t        j                  d|        Y yw xY w)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   r>   rR   warning)upstream_versionfull_versions     r   get_opensshd_upstream_versionr    s     ')L||$$%566
l'(@,*;*;C*@A		'(@,*;*;C*@A'J<<001AB	" J68HIJs   # B %B,+B,r   )*loggingrJ   rg   
contextlibr   typingr   r   r   	cloudinitr   r   	getLoggerr%   rR   r   r?   _DISABLE_USER_SSH_EXITr^   DISABLE_USER_OPTSr   r*   rX   re   rm   r|   r   r   r   r   r   r   r   r   boolr   r   r   r   r   r	  r  r(   r   r   <module>r     s8    	 
  ( (  g! & ,   ()* -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   