o ã&µ`tOã@sddlmZddlmZddlmZddlmZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlZddlmZddlmZdd lmZdd lmZd ZGd d „d ejjƒZej de¡ej de¡ej de¡ej de¡ejj gd¢¡dS)é)Údivision)Úinput)Úoct)ÚzipN)Úhexlify)Úprogress)Úconfig)Úutil)ÚBackendExceptionicc@sJeZdZdZdd„Zdd„Zdd„Zdd „Zd d „Zddd„Z dd„Z dS)ÚSSHParamikoBackendaÜThis backend accesses files using the sftp or scp protocols. It does not need any local client programs, but an ssh server and the sftp program must be installed on the remote side (or with scp, the programs scp, ls, mkdir, rm and a POSIX-compliant shell). Authentication keys are requested from an ssh agent if present, then ~/.ssh/id_rsa/dsa are tried. If -oIdentityFile=path is present in --ssh-options, then that file is also tried. The passphrase for any of these keys is taken from the URI or FTP_PASSWORD. If none of the above are available, password authentication is attempted (using the URI or FTP_PASSWORD). Missing directories on the remote side will be created. If scp is active then all operations on the remote side require passing arguments through a shell, which introduces unavoidable quoting issues: directory and file names that contain single quotes will not work. This problem does not exist with sftp. cs„tjj ||¡d|_|jrt dd|jd¡|_nd|_t   ¡t   d¡zddl a Wnt y4‚wWdƒn1s?wYG‡fdd „d t jƒ}Gd d „d t jƒ‰t  ¡|_|j |ƒ¡|j d ¡t j d ¡}t tj¡}| t d ¡¡| |¡t d¡ ¡}|dkr’tj}n|dkrštj }n|dkr¢tj!}n |dkrªtj"}ntj#}| $|¡d}t %dt&j'tj(¡}|durÐ| )d¡rË| )d¡n| )d¡}zt*j +|¡rÝ|j ,|¡Wnt-yò} zt.d|›dƒ‚d} ~ wwt*j /d¡} t %dt&j'tj(¡}|dur| )d¡r| )d¡n| )d¡} zt*j +| ¡r&|j 0| ¡n| |j_1Wnt-y@} zt.d| ›dƒ‚d} ~ ww d|j2i|_&|j& 3| 4d|j2¡¡|j& 3| 4d|j2¡¡|j5rk|j& 3d|j5i¡d|j&vr{|j& 3dt6 7¡i¡|j8rˆ|j& 3d|j8i¡d|j&vrœ|j& 3dt9|j&dƒi¡n|j& 3ddi¡t %dt&j'tj(¡}|durÊ| )d¡r½| )d¡n| )d¡} |  :d ¡|j&d!<d!|j&vrðt;|j&d!t<ƒsâ|j&d!g|j&d!<d"d#„|j&d!Dƒ|j&d!<nd|j&d!<t&j=|_>|j&d|_5|j&d|_2| ?¡} z|jj@|j&d|j&d|j&d| d$d$|j&d!d%Wn t-yD} zt.d&|j&d|j&d|j&d| fƒ‚d} ~ ww|j A¡ Bt9t&jCd'ƒ¡tj D|jEd(¡|_E|jEd)k|_F|jFr~t %d*|j¡rqt.d+ƒ‚| Gd,|jfd-d.¡dSz|j H¡|_IWnt-y™} zt.d/| ƒ‚d} ~ ww|j Jt*jK¡} tL| ƒdkr>| ddkr³d0| d<| D]Š}|dkr¾qµz|jI M|¡}WnPtNy} zC| jOtOjPkrüz|jI Q|¡Wn-t-yû} zt.d1|jI Rd¡d0|| fƒ‚d} ~ wwt.d2|jI Rd¡d0|| fƒ‚WYd} ~ nd} ~ wwz |jI S|¡Wqµt-y=} zt.d3|jI Rd¡d0|| fƒ‚d} ~ wwdSdS)4Né z^/ÚéÚ.ÚignorercseZdZdZ‡fdd„ZdS)z4SSHParamikoBackend.__init__..AgreedAddPolicyzö Policy for showing a yes/no prompt and adding the hostname and new host key to the known host file accordingly. This class simply extends the AutoAddPolicy class with a yes/no prompt. c s t| ¡ƒ}d dd„tt|ddd…|ddd…ƒƒDƒ¡}d|| ¡ ¡|f} tj  |¡t ƒ  ¡}|dvrEt j  ||||¡dS|d vrMˆ|ƒ‚d }q+) Nú:css |] \}}t||ƒVqdS)N)Ústr)Ú.0ÚaÚb©rúI/usr/lib/python3/dist-packages/duplicity/backends/ssh_paramiko_backend.pyÚ is€zXSSHParamikoBackend.__init__..AgreedAddPolicy.missing_host_key..érz…The authenticity of host '%s' can't be established. %s key fingerprint is %s. Are you sure you want to continue connecting (yes/no)? T)ÚyesÚy)ÚnoÚnzPlease type 'yes' or 'no': )rÚget_fingerprintÚjoinÚlistrÚget_nameÚupperÚsysÚstdoutÚwriterÚlowerÚparamikoÚ AutoAddPolicyÚmissing_host_key)ÚselfÚclientÚhostnameÚkeyÚfpÚ fingerprintÚquestionÚchoice©ÚAuthenticityExceptionrrr)gs( 2 þþ   ÿözESSHParamikoBackend.__init__..AgreedAddPolicy.missing_host_keyN)Ú__name__Ú __module__Ú __qualname__Ú__doc__r)rr2rrÚAgreedAddPolicy_sr8c@seZdZdd„ZdS)z:SSHParamikoBackend.__init__..AuthenticityExceptioncSstj |d|¡dS)Nz+Host key verification for server %s failed.)r'Ú SSHExceptionÚ__init__)r*r,rrrr:|s ÿÿzCSSHParamikoBackend.__init__..AuthenticityException.__init__N)r4r5r6r:rrrrr3{s r3Ú sshbackendzssh: %(message)sÚ duplicityééé z/etc/ssh/ssh_known_hostsa; ^(?:.+\s+)? (?:-oGlobalKnownHostsFile=) ( ([\"']) ([^\\2]+) \\2 | [\S]+ ) ézcould not load z, maybe corrupt?z~/.ssh/known_hostsa9 ^(?:.+\s+)? (?:-oUserKnownHostsFile=) ( ([\"']) ([^\\2]+) \\2 | [\S]+ ) r,z/etc/ssh/ssh_configz ~/.ssh/configÚuserÚportéa ^(?:.+\s+)? (?:-oIdentityFile=|-i\s+) (([\"']) ( [^\\2]+)\\2 | [\S]+ ) z'"Ú identityfilecSsg|]}tj |¡‘qSr)ÚosÚpathÚ expanduser)rÚirrrÚ s ÿz/SSHParamikoBackend.__init__..T)r,rBÚusernameÚpasswordÚ allow_agentÚ look_for_keysÚ key_filenamez%ssh connection to %s@%s:%d failed: %srr'Úscpú'z9cannot handle directory names with single quotes with scpz mkdir -p '%s'Fz scp mkdir zsftp negotiation failed: %sú/zsftp mkdir %s failed: %szsftp stat %s failed: %szsftp chdir to %s failed: %s)Tr<ÚbackendÚBackendr:Ú retry_delayrFÚreÚsubÚ remote_dirÚwarningsÚcatch_warningsÚ simplefilterr'Ú ImportErrorr(r9Ú SSHClientr+Úset_missing_host_key_policyÚset_log_channelr Ú get_loggerÚloggingÚ StreamHandlerr#ÚstderrÚ setFormatterÚ FormatterÚ addHandlerÚ getLoggerÚgetEffectiveLevelÚDEBUGÚINFOÚWARNINGÚERRORÚCRITICALÚsetLevelÚsearchrÚ ssh_optionsÚVERBOSEÚgrouprEÚisfileÚload_system_host_keysÚ Exceptionr rGÚload_host_keysÚ_host_keys_filenamer,ÚupdateÚ gethostconfigrJÚgetpassÚgetuserrBÚintÚstripÚ isinstancer Ú ssh_askpassÚ use_getpassÚ get_passwordÚconnectÚ get_transportÚ set_keepaliveÚtimeoutÚ strip_prefixÚschemeÚuse_scpÚ runremoteÚ open_sftpÚsftpÚsplitÚsepÚlenÚstatÚIOErrorÚerrnoÚENOENTÚmkdirÚ normalizeÚchdir)r*Ú parsed_urlr8ÚoursÚdestÚplevelÚwantedÚglobal_known_hostsÚmÚeÚuser_known_hostsÚ keyfilenamerKÚdirsÚdÚattrsrr2rr:GsH    ÿÿý       õ   €€ÿ  õ €€ÿ  ÿ ÿ   ö   ÿ    ú ý€ÿ ÿ  €ÿ ÿ€ÿÿ û€ý ÿ€ÿìzSSHParamikoBackend.__init__c Cs‚t |¡}|jr´t|jdƒ}z|j ¡ ¡}| t j ¡|  d|j ¡Wnt y7}ztd|ƒ‚d}~ww| d¡}|dkrJtd| d¡ƒ‚t |j¡}| dt|jƒd d…|j|f¡| d¡}|dkrttd| d¡ƒ‚d }|j} || kr“| | d ¡¡| ¡}t || ¡|| ks}| d¡| ¡| d¡}|dkr®td | d¡ƒ‚| ¡dS|jj|j|tjd dS)NÚrbz scp -t '%s'úscp execution failed: %srósscp remote error: %béÿÿÿÿz C%s %d %s éüÿÿÿri@zscp remote error: %s)Úcallback)r Úfsdecoder‡ÚopenÚnamer+r‚Ú open_sessionÚ settimeoutrr„Ú exec_commandrWrtr ÚrecvrErŽÚsendrÚst_modeÚst_sizeÚsendallÚreadÚtellrÚreport_transferÚcloserŠÚput) r*Ú source_pathÚremote_filenameÚfÚchanrœÚresponseÚfstatÚfile_posÚ file_sizerrrÚ_putKsF    €ÿ  ÿ  ý   zSSHParamikoBackend._putc Cs¼t |¡}|jrÔz|j ¡ ¡}| tj¡|  d|j |f¡Wnt y3}zt d|ƒ‚d}~ww|  d¡| d¡}t|tƒrG| ¡}t d|¡}|dusX| d¡|kr`t d||fƒ‚| d¡t| d ¡ƒ}|}t|jd ƒ} |  d¡z#|d kr›|tkr…t} n|} | | ¡} |  | ¡|t| ƒ8}|d ks~Wnt y°}zt d ||fƒ‚d}~ww| d¡}|d krÅt d || d¡fƒ‚|  ¡|  d¡| ¡dS|j ||j¡dS)Nzscp -f '%s/%s'r£úr¥zC([0-7]{4})\s+(\d+)\s+(\S.*)$r@z*scp get %s failed: incorrect response '%s'rrÚwbrzscp get %s failed: %sr¤)r r¨r‡r+r‚r«r¬rr„r­rWrtr r¯r®r}ÚbytesÚdecoderUÚmatchrqr{r©rªÚread_blocksizer%rr¶rŠÚget) r*r¹Ú local_pathr»rœÚmsgr›ÚsizeÚtogorºÚ blocksizeÚbuffrrrÚ_getrsb    ÿ €ÿ    ÿ      ù€€ÿ ÿ  zSSHParamikoBackend._getcCs,|jr| d|jdd¡}| ¡S|j ¡S)Nz ls -1 '%s'Fzscp dir listing )r‡rˆrWÚ splitlinesrŠÚlistdir)r*ÚoutputrrrÚ_list¢s ÿ zSSHParamikoBackend._listcCs<t |¡}|jr| d|j|fdd¡dS|j |¡dS)Nz rm '%s/%s'Fzscp rm )r r¨r‡rˆrWrŠÚremove)r*ÚfilenamerrrÚ_delete¬s ÿzSSHParamikoBackend._deleteFr c Cslz|j |dtj¡\}}}| d¡}|WSty5}z|s*td||t |¡fƒ‚WYd}~dSd}~ww)z­small convenience function that opens a shell channel, runs remote command and returns stdout of command. throws an exception if exit code!=0 and not ignoredr¥z%sfailed: %s %sN) r+r­rr„r³rtr r Úuexc) r*ÚcmdÚignoreexitcodeÚ errorprefixÚch_inÚch_outÚch_errrÑrœrrrrˆ·s  ÿÿ€ÿzSSHParamikoBackend.runremotec Csftj |¡}tj |¡siSt ¡}z | t|ƒ¡Wnty-}zt d|ƒ‚d}~ww|  |¡S)Nz#could not load '%s', maybe corrupt?) rErFrGrrr'Ú SSHConfigÚparser©rtr Úlookup)r*ÚfileÚhostÚ sshconfigrœrrrrxÄs   €ÿ z SSHParamikoBackend.gethostconfigN)Fr ) r4r5r6r7r:rÀrÎrÒrÕrˆrxrrrrr 3s'0 r rŠrOú paramiko+sftpú paramiko+scp)rŠrOrãrä)Ú __future__rÚbuiltinsrrrrryr`rErUr#rXÚbinasciirÚduplicity.backendr<rrr Úduplicity.errorsr rÆrRrSr Úregister_backendÚ uses_netlocÚextendrrrrÚs6         "