fXddlZddlZddlZddlmZddlmZmZmZddl m Z m Z eje ZdZdZdZdeezd zZGd d ZGd d ZdZdZdZdZdZdZefdZd%dZGddZdeefdZdeefdZ dZ!dede"fdZ#dZ$efdZ%d Z&efd!eeeeffd"Z'd#Z(d$Z)y)&N)suppress)ListSequenceTuple)subputilz/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  \r N)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:)splitr/ TypeErrorVALID_KEY_TYPESr!)r1r#s r parse_ssh_keyz.AuthKeyLineParser.parse..parse_ssh_keysp99T1%D4y1} 3c$i ?@@Awo- 4tAw >??4yA~ BKr)rrrr)rstrip startswithstriprr>r7) rsrc_linerliner@r1rrrkeyoptsr6s 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__r7rGr(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*ospathisfilerload_text_file splitlinesr!rGIOErrorOSErrorlogexcLOG)fnameslinesparsercontentsfnamerEs rparse_authorized_keysrXs 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: ) listrranger/rremover!strr") old_entrieskeyskto_addr3r1keybrTs rupdate_authorized_keysres 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 RuntimeErrorrJrKr")usernamepw_ents rusers_ssh_informsH \\( #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=replacerBrJrKr"r!) valuehomedirrkmacrospathsrenderedrKmacrofields 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 zd k7rtjd ||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_ownerrRdebugget_permissions get_groupget_user_groups) rk current_path full_pathis_file strictmodesminimal_permissionsownerparent_permission group_owner user_groupss rcheck_permissionsrs # NN< (Eu(Uf_  @      ,,\: u$nn\2 **84 + % 5 (  5 ( ..!3  %     (50A5  @     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-r~rsr: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)rmr=rJrKdirnameriislinkrRrrLrBexistsr SeLinuxGuardpw_uidpw_gidmakedirs chownbyidrisdir write_filerOrPrQr^)rkfilenamer 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 < >   $  !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!rGr^rrJrKrrrrer) r`rkrrU key_entriesrarauth_key_entriesrcontents rsetup_user_keysrs  FK B6<<A<@AB'>h&G#["ggook*G  7d 3B()9;G  WDABBBs %B11B:c*eZdZddZedZdZy)SshdConfigLineNc.||_||_||_yr)rE_keyru)rrEravs rrzSshdConfigLine.__init__s   rcP|jy|jjSr)rlowerrs rrczSshdConfigLine.keys 99 yy  rc|jt|jSt|j}|jr|dt|jzz }|Sr)rr^rEru)rrs rr$zSshdConfigLine.__str__sJ 99 tyy> !DIIAzzS3tzz?**Hr)NN)r%r&r'rpropertyrcr$r(rrrrs  !! rrreturnctjj|sgStt j |j Sr)rJrKrLparse_ssh_config_linesrrMrNrWs 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)Nr9r-=z;sshd_config: option "%s" has no key/value pair, skipping it)rCrBr!rr= ValueErrorrRr)rTretrErcvals rrrs !#C3zz|ts+ JJ~d+ ,  zz$*HC >$S12#3$ J  ::c1-S  #    s6A<< CBCB?;C>B??CCct|}|siSi}|D](}|js|j||j<*|Sr)rrcru)rWrTrrEs rrrsJ U #E  C#xx  DHH # JrrWctjj|syt|d5}|D]!}|j d|dsdddy dddy#1swYyxYw)NFrzInclude z .d/*.confT)rJrKrLopenrB)rWfrEs r_includes_dconfr"sl 77>>%  eS Q D% :;    sA AAA'cDt|rtjj|dst j |ddtjj |dd}tjj|st j|d|S)Nz.dr)rz50-cloud-init.confr) rrJrKrr ensure_dirr"rL 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.)rTupdatesrZTrr)rrupdate_ssh_config_linesrrr"r^r/)rrWrTchangedrEs rupdate_ssh_configr7so /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)setdictr`r enumeratercaddrurRrr!r/itemsr) rTrfoundrracasemapr3rErcrus rrrHs\ EEGGLLN;qQWWYN;z$append_ssh_config..zs,da!AaSz,srZabT)omoder)rrrr")rTrWrs rappend_ssh_configrvsB  .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_rZ,)rrProcessExecutionErrorr=rBr/find)err_prefixrEs rget_opensshd_versionr s 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) r rVersionfrom_strrrr>rRwarning)upstream_version full_versions rget_opensshd_upstream_versionrs')L||$$%566 l'(@,*;*;C*@A '(@,*;*;C*@A'J<<001AB  "J 68HIJs# B%B,+B,r)*loggingrJrg contextlibrtypingrrr cloudinitrr getLoggerr%rRrr?_DISABLE_USER_SSH_EXITr^DISABLE_USER_OPTSrr*rXrermr|rrrrrrrrboolrrrrrr rr(rrrs8 (( g!& , ()*-00"":V V r  89*BJL^5A6r B.KtN3K T.%96 34&2"+\?K XeCHo6 (Jr