o &`tO@sddlmZddlmZddlmZddlmZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlZddlmZddlmZdd lmZdd lmZd ZGd d d ejjZejdeejdeejdeejdeejjgddS))division)input)oct)zipN)hexlify)progress)config)util)BackendExceptionicc@sJeZdZdZddZddZddZdd Zd d ZdddZ ddZ dS)SSHParamikoBackendaThis 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. cstjj||d|_|jrtdd|jd|_nd|_t t dzddl a Wnt y4wWdn1s?wYGfdd d t j}Gd d d t jt |_|j||jd t jd }ttj}|td ||td}|dkrtj}n|dkrtj }n|dkrtj!}n |dkrtj"}ntj#}|$|d}t%dt&j'tj(}|dur|)dr|)dn|)d}zt*j+|r|j,|Wnt-y} zt.d|dd} ~ wwt*j/d} t%dt&j'tj(}|dur|)dr|)dn|)d} zt*j+| r&|j0| n| |j_1Wnt-y@} zt.d| dd} ~ ww d|j2i|_&|j&3|4d|j2|j&3|4d|j2|j5rk|j&3d|j5id|j&vr{|j&3dt67i|j8r|j&3d|j8id|j&vr|j&3dt9|j&din|j&3ddit%dt&j'tj(}|dur|)dr|)dn|)d} | :d |j&d!<d!|j&vrt;|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| fd} ~ ww|jABt9t&jCd'tjD|jEd(|_E|jEd)k|_F|jFr~t%d*|jrqt.d+|Gd,|jfd-d.dSz|jH|_IWnt-y} zt.d/| d} ~ ww|jJt*jK} tL| dkr>| ddkrd0| d<| D]}|dkrqz|jIM|}WnPtNy} zC| jOtOjPkrz|jIQ|Wn-t-y} zt.d1|jIRdd0|| fd} ~ wwt.d2|jIRdd0|| fWYd} ~ nd} ~ wwz |jIS|Wqt-y=} zt.d3|jIRdd0|| fd} ~ wwdSdS)4N z^/.ignorercseZdZdZfddZdS)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 st|}dddtt|ddd|dddD}d|||f} tj |t }|dvrEt j ||||dS|d vrM|d }q+) N:css |] \}}t||VqdS)N)str).0abrI/usr/lib/python3/dist-packages/duplicity/backends/ssh_paramiko_backend.py iszXSSHParamikoBackend.__init__..AgreedAddPolicy.missing_host_key..rzThe authenticity of host '%s' can't be established. %s key fingerprint is %s. Are you sure you want to continue connecting (yes/no)? T)yesy)nonzPlease type 'yes' or 'no': )rget_fingerprintjoinlistrget_nameuppersysstdoutwriterlowerparamiko AutoAddPolicymissing_host_key)selfclienthostnamekeyfp fingerprintquestionchoiceAuthenticityExceptionrrr)gs( 2    zESSHParamikoBackend.__init__..AgreedAddPolicy.missing_host_keyN)__name__ __module__ __qualname____doc__r)rr2rrAgreedAddPolicy_sr8c@seZdZddZdS)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/configuserporta ^(?:.+\s+)? (?:-oIdentityFile=|-i\s+) (([\"']) ( [^\\2]+)\\2 | [\S]+ ) z'" identityfilecSsg|]}tj|qSr)ospath expanduser)rirrr s z/SSHParamikoBackend.__init__..T)r,rBusernamepassword 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<backendBackendr: retry_delayrFresub remote_dirwarningscatch_warnings simplefilterr' ImportErrorr(r9 SSHClientr+set_missing_host_key_policyset_log_channelr get_loggerlogging StreamHandlerr#stderr setFormatter Formatter addHandler getLoggergetEffectiveLevelDEBUGINFOWARNINGERRORCRITICALsetLevelsearchr ssh_optionsVERBOSEgrouprEisfileload_system_host_keys Exceptionr rGload_host_keys_host_keys_filenamer,update gethostconfigrJgetpassgetuserrBintstrip isinstancer ssh_askpass use_getpass get_passwordconnect get_transport set_keepalivetimeout strip_prefixschemeuse_scp runremote open_sftpsftpsplitseplenstatIOErrorerrnoENOENTmkdir normalizechdir)r* parsed_urlr8oursdestplevelwantedglobal_known_hostsmeuser_known_hosts keyfilenamerKdirsdattrsrr2rr:GsH                                     zSSHParamikoBackend.__init__c Cst|}|jrt|jd}z|j}|t j | d|j Wnt y7}ztd|d}~ww|d}|dkrJtd|dt|j}|dt|jd d|j|f|d}|dkrttd|dd }|j} || kr||d |}t|| || ks}|d||d}|dkrtd |d|dS|jj|j|tjd dS)Nrbz scp -t '%s'scp execution failed: %srsscp remote error: %bz C%s %d %s ri@zscp remote error: %s)callback)r fsdecoderopennamer+r open_session settimeoutrr exec_commandrWrtr recvrErsendrst_modest_sizesendallreadtellrreport_transfercloserput) r* source_pathremote_filenamefchanrresponsefstatfile_pos file_sizerrr_putKsF           zSSHParamikoBackend._putc Cst|}|jrz|j}|tj| d|j |fWnt y3}zt d|d}~ww| d|d}t|trG|}td|}|dusX|d|kr`t d||f|dt|d }|}t|jd } | dz#|d kr|tkrt} n|} || } | | |t| 8}|d ks~Wnt y}zt d ||fd}~ww|d}|d krt d ||df| | d|dS|j||jdS)Nzscp -f '%s/%s'rrzC([0-7]{4})\s+(\d+)\s+(\S.*)$r@z*scp get %s failed: incorrect response '%s'rrwbrzscp get %s failed: %sr)r rrr+rrrrrrrWrtr rrr}bytesdecoderUmatchrqr{rrread_blocksizer%rrrget) r*r local_pathrrmsgrsizetogor blocksizebuffrrr_getrsb                  zSSHParamikoBackend._getcCs,|jr|d|jdd}|S|jS)Nz ls -1 '%s'Fzscp dir listing )rrrW splitlinesrlistdir)r*outputrrr_lists  zSSHParamikoBackend._listcCs<t|}|jr|d|j|fdddS|j|dS)Nz rm '%s/%s'Fzscp rm )r rrrrWrremove)r*filenamerrr_deletes zSSHParamikoBackend._deleteFr c Cslz|j|dtj\}}}|d}|WSty5}z|s*td||t|fWYd}~dSd}~ww)zsmall convenience function that opens a shell channel, runs remote command and returns stdout of command. throws an exception if exit code!=0 and not ignoredrz%sfailed: %s %sN) r+rrrrrtr r uexc) r*cmdignoreexitcode errorprefixch_inch_outch_errrrrrrrs  zSSHParamikoBackend.runremotec Csftj|}tj|siSt}z |t|Wnty-}zt d|d}~ww| |S)Nz#could not load '%s', maybe corrupt?) rErFrGrrr' SSHConfigparserrtr lookup)r*filehost sshconfigrrrrrxs    z SSHParamikoBackend.gethostconfigN)Fr ) r4r5r6r7r:rrrrrrxrrrrr 3s'0 r rrO paramiko+sftp paramiko+scp)rrOrr) __future__rbuiltinsrrrrryr`rErUr#rXbinasciirduplicity.backendr<rrr duplicity.errorsr rrRrSr register_backend uses_netlocextendrrrrs6         "