x[hXddlZddlZddlZddlmZddlmZmZmZddl m Z m Z m Z ejeZdZdZdZdeezd zZGd d ZGd d ZdZdZdZdZdZdZefdZd%dZGddZdeefdZ deefdZ!dZ"dede#fdZ$dZ%efdZ&d Z'efd!eeeeffd"Z(d#Z)d$Z*y)&N)suppress)ListSequenceTuple) lifecyclesubputilz/etc/ssh/sshd_config)rsaecdsaed25519z(ecdsa-sha2-nistp256-cert-v01@openssh.comzecdsa-sha2-nistp256z(ecdsa-sha2-nistp384-cert-v01@openssh.comzecdsa-sha2-nistp384z(ecdsa-sha2-nistp521-cert-v01@openssh.comzecdsa-sha2-nistp521z+sk-ecdsa-sha2-nistp256-cert-v01@openssh.comz"sk-ecdsa-sha2-nistp256@openssh.comz#sk-ssh-ed25519-cert-v01@openssh.comzsk-ssh-ed25519@openssh.comz ssh-ed25519-cert-v01@openssh.comz ssh-ed25519zssh-rsa-cert-v01@openssh.comzssh-rsazssh-xmss-cert-v01@openssh.comzssh-xmss@openssh.comzno-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"eZdZ ddZdZdZy) AuthKeyLineNcJ||_||_||_||_||_yN)base64commentoptionskeytypesource)selfrrrrrs 4/usr/lib/python3/dist-packages/cloudinit/ssh_util.py__init__zAuthKeyLine.__init__Es'     c6|jxr |jSr)rrrs rvalidzAuthKeyLine.validNs{{+t||+rc|g}|jr|j|j|jr|j|j|jr|j|j|jr|j|j|s |j Sdj |SN )rappendrrrrjoin)rtokss r__str__zAuthKeyLine.__str__Qs~ << KK % << KK % ;; KK $ << KK %;; 88D> !r)NNNN)__name__ __module__ __qualname__rrr%rrrrDsGK, "rrceZdZdZdZddZy)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|krc|s||dvrZ||}|dzt|k\r|dz}n>||dz}|dk(r |dk(r|dz}n|dk(r| }|dz}|t|kr |rR||dvrZ|d|}||dj}||fS)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! \rN)lenlstrip)rentquotedicurcnextcrremains r_extract_optionsz"AuthKeyLineParser._extract_optionsus  #c(lSV;-Fq6D1uC EAJEt| E#AA#c(lSV;-Fa(QR!  rNc|jd}|jds|jdk(r t|Sd}|j} ||\}}}t|||||S#t$rE|j |\} } || } || \}}}n#t$rt|cYcYSwxYwY]wxYw)Nz #c|jdd}t|dkrtdt|z|dtvrtd|dzt|dk(r|j d|S)NzTo few fields: %srzInvalid keytype %sr;)splitr0 TypeErrorVALID_KEY_TYPESr")r2r$s r parse_ssh_keyz.AuthKeyLineParser.parse..parse_ssh_keysp99T1%D4y1} 3c$i ?@@Awo- 4tAw >??4yA~ BKr)rrrr)rstrip startswithstriprr?r8) rsrc_linerlinerAr2rrrkeyoptsr7s rparsezAuthKeyLineParser.parsesv& ??3 4::<2#5x( ( jjl -)6s); &Wfg     - $ 5 5c : Wf! --:6-B*&' -"8,, -#*  -s6 A11!B? B B? B94B?8B99B?>B?r)r&r'r(__doc__r8rHr)rrr+r+as&!4( rr+cdg}t}g}|D]l} tjj|rJt j |j }|D]"}|j|j|$n|S#ttf$rt jtd|YwxYw)NzError reading lines from %s) r+ospathisfiler load_text_file splitlinesr"rHIOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerFs rparse_authorized_keysrYs E  FHC Cww~~e$++E2==?!8DOOFLL$678 C O! C KK:E B CsA)B*B/.B/ct|Dcgc]}|js|c}}tt|D]V}||}|js|D]4}|j|jk(s|}||vs$|j |6|||<X|D]}|j ||Dcgc] }t|}}|j ddj|Scc}wcc}w)Nr; ) listrranger0rremover"strr#) old_entrieskeyskto_addr4r2keybrUs rupdate_authorized_keysrfs d0aggi10 1F 3{# $ !nyy{  %Axx3::%;MM!$  % A  3 ) )SV )E ) LL 99U 11( *sC*C*4C/ctj|}|r |jstd|ztj j |jd|fS)Nz"Unable to get SSH info for user %rz.ssh)pwdgetpwnampw_dir RuntimeErrorrKrLr#)usernamepw_ents rusers_ssh_infornsH \\( #F ?8LMM GGLL / 88rcd|fd|fdf}|sd}|j}g}|D]`}|D]\}}|j||}|jds tjj ||}|j |b|S)N%h%u)z%%%%h/.ssh/authorized_keys/)r>replacerCrKrLr#r") valuehomedirrlmacrospathsrenderedrLmacrofields rrender_authorizedkeysfile_pathsr}s Woh/ =F ) KKMEH" .LE5<<u-D .s#77<<.D  Orcd}|rd}tj|}|r$||k7r|dk7rtjd||||ytj|}||k(r|dz}n9tj |}tj |} || vr|dz}n|dz}||zd k(rtjd |||y|r|d zrtjd ||yy )aVCheck 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) iirootzXPath %s in %s must be own by user %s or by root, but instead is own by %s. Ignoring key.F8rzBPath %s in %s must be accessible by user %s, check its permissionszRPath %s in %s must not give writepermission to group or world users. Ignoring key.T)r get_ownerrSdebugget_permissions get_groupget_user_groups) rl current_path full_pathis_file strictmodesminimal_permissionsownerparent_permission group_owner user_groupss rcheck_permissionsrs # NN< (Eu(Uf_  @      ,,\: u$nn\2 **84 + % 5 (  5 ( ..!3  %     )E1  @     rct|d}tdd} |jddd}d}tjj |j }|D]h}|d|zz }tjj |rtjd|ytjj|rtjd|y|j|s||j k(rtjj|stj|5d } |j} |j} |j|j rd } |j} |j} tj || d tj"|| | dddt%|||d|} | riytjj |stjj'|rtjd |ytjj|sDtj(|ddd tj"||j|jt%|||d |} | sy y #1swYxYw#t*t,f$r-} tj.tt1| Yd} ~ yd} ~ wwxYw)Nr.rrtr;z-Invalid directory. Symlink exists in path: %sFz*Invalid directory. File exists in path: %srT)modeexist_okz%s is not a file!)rensure_dir_exists)rnr>rKrLdirnamerjislinkrSrrMrCexistsr SeLinuxGuardpw_uidpw_gidmakedirs chownbyidrisdir write_filerPrQrRr_)rlfilenamer user_pwent root_pwent directories parent_folder home_folder directoryruidgid permissionses rcheck_create_pathrGsr)!,J'*JGnnS)!B/  ggooj&7&78 $* I S9_ ,Mww~~m, C!ww~~m, @-&&}5 J$5$5577>>-0&&}5 < D$++C$++C$// 0A0AB$(//(//KK D4HNN=#s; <,-5+KU* X 77>>( #rww}}X'> II)8 4ww~~h' OOHbu M NN8Z%6%6 8I8I J' h$   K < anyrCformatrrrY) rl sshd_cfg_filessh_dirrmdefault_authorizedkeys_fileuser_authorizedkeys_file auth_key_fnsssh_cfg key_pathsrkey_path auth_key_fnpermissions_oks rextract_authorized_keysrs&x0Wf"$'',,w8I"J:L  7d 3 *=9G $&?I"++mU;K:6==(L0"%Y__%6 !E +   &&u||FMM'BC  /+{e';N+6(  #>>   $  !789 G! 9LO KKQ   s+ E3 AD667E0-E3/E00E33E<czt}g}|D]-}|j|jt||/t |\}}t j j|}tj|d5t||} tj|| ddddy#1swYyxYw)N)rTr preserve_mode) r+r"rHr_rrKrLrr rrfr) rarlrrV key_entriesrbrauth_key_entriesrcontents rsetup_user_keysrs  FK B6<<A<@AB'>h&G#["ggook*G  7d 3B()9;G  WDABBBs %B11B:c*eZdZddZedZdZy)SshdConfigLineNc.||_||_||_yr)rF_keyrv)rrFrbvs rrzSshdConfigLine.__init__s   rcP|jy|jjSr)rlowerrs rrdzSshdConfigLine.keys 99 yy  rc|jt|jSt|j}|jr|dt|jzz }|Sr )rr_rFrv)rrs rr%zSshdConfigLine.__str__sJ 99 tyy> !DIIAzzS3tzz?**Hr)NN)r&r'r(rpropertyrdr%r)rrrrs  !! rrreturnctjj|sgStt j |j Sr)rKrLrMparse_ssh_config_linesr rNrOrXs rparse_ssh_configrs6 77>>%  !$"5"5e"<"G"G"I JJrcg}|D]r}|j}|r|jdr|jt|A |j dd\}}|jt|||t|S#t $r@ |j dd\}}n&#t $rt jd|YYwxYwYhwxYw)Nr:r.=z;sshd_config: option "%s" has no key/value pair, skipping it)rDrCr"rr> ValueErrorrSr)rUretrFrdvals rrrs !#C3zz|ts+ JJ~d+ ,  zz$*HC >$S12#3$ J  ::c1-S  #    s6A<< CBCB?;C>B??CCct|}|siSi}|D](}|js|j||j<*|Sr)rrdrv)rXrUrrFs rrrsJ U #E  C#xx  DHH # JrrXctjj|sytj|j D]}|j d|dsyy)NFzInclude z .d/*.confT)rKrLrMr rNrOrC)rXrFs r_includes_dconfr"sU 77>>% ##E*557 ??XeWI6 7 rcDt|rtjj|dst j |ddtjj |dd}tjj|st j|d|S)Nz.dr)rz50-cloud-init.confr) rrKrLrr ensure_dirr#rM ensure_filers r"_ensure_cloud_init_ssh_config_filer+stuww}}wb\* OOugRLu 5 wb\+?@ww~~e$   UE * Lrc t|}t|}t||}|rAtj|dj |Dcgc] }t |c}dzdt|dk7Scc}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.)rUupdatesr[Trr)rrupdate_ssh_config_linesr rr#r_r0)rrXrUchangedrFs rupdate_ssh_configr6so /u 5E U #E%E7CG   IIU3Ts4y3 4t ; w<1 4sA5c t}g}t|jDcgc]}|j|fc}}t |dD]\}}|j s|j |vs"||j }||} |j ||j| k(rtjd||| o|j|tjd|||j| | |_t|t|k7rk|jD]X\}} ||vr |j||jtd|| tjdt||| Z|Scc}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)setdictrar enumeraterdaddrvrSrr"r0itemsr) rUrfoundrrbcasemapr4rFrdrvs rrrGs\ EEGGLLN;qQWWYN;z$append_ssh_config..ys,da!AaSz,sr[abT)omoder)rr rr#)rUrXrs rappend_ssh_configrusB  .u 5E,e,GOO  'T! rc0d}ttj5tjddgddg\}}dddd}|jd D]2}|j |s|t ||j d cSy#1swYRxYw) 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-Vrr.)rcsNOpenSSH_r[,)rrProcessExecutionErrorr>rCr0find)err_prefixrFs rget_opensshd_versionrs C $,, -7FD>1v637 F $6 ??6 "F diin5 56  77s B  Bc^d}t}|tjj|Sd|vr|d|j d}nd|vr|d|j d}n|} tjj|}|S#t t f$rtjd|YywxYw)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` z9.0Npr!z Could not parse sshd version: %s) rrVersionfrom_strrrr?rSwarning)upstream_version full_versions rget_opensshd_upstream_versionrs')L  ))*:;; l'(@,*;*;C*@A '(@,*;*;C*@A'J$,,556FG  "J 68HIJs# B%B,+B,r)+loggingrKrh contextlibrtypingrrr cloudinitrrr getLoggerr&rSrr@_DISABLE_USER_SSH_EXITr_DISABLE_USER_OPTSrr+rYrfrnr}rrrrrrrrboolrrrrrrrr)rrrs; ((++g!& , ()*-00"":V V r  89*BJL^5A6r B.KtN3K T.%96 34&2"+\?K XeCHo6 (Jr