/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "ResMgr.h" #include "url.h" #include "GetPass.h" #include "ascii_ctype.h" #include "configmake.h" #include "misc.h" #include "localcharset.h" static const char *FtpProxyValidate(xstring_c *p) { ParsedURL url(*p); if(url.host==0) { p->truncate(0); return 0; } if(url.proto) { if(strcmp(url.proto,"ftp") && strcmp(url.proto,"http")) return _("Proxy protocol unsupported"); } if(url.user && !url.pass) { url.pass.set(GetPass(_("ftp:proxy password: "))); p->truncate(); url.CombineTo(*p); } return 0; } static const char *SetValidate(xstring_c& s,const char *const *set,const char *name) { const char *const *scan; for(scan=set; *scan; scan++) if(s.eq(*scan)) return 0; xstring &j=xstring::get_tmp(); if(name) j.setf(_("%s must be one of: "),name); else j.set(_("must be one of: ")); bool had_empty=false; for(scan=set; *scan; scan++) { if(!**scan) { had_empty=true; continue; } if(scan>set) j.append(", "); j.append(*scan); } if(had_empty) j.append(_(", or empty")); return j; } static const char *FtpProxyAuthTypeValidate(xstring_c *s) { static const char *const valid_set[]={ "user", "joined", "joined-acct", "open", "proxy-user@host", 0 }; return SetValidate(*s,valid_set,"ftp:proxy-auth-type"); } static const char *HttpProxyValidate(xstring_c *p) { ParsedURL url(*p); if(url.host==0) { p->truncate(0); return 0; } if(url.proto) { if(strcmp(url.proto,"http") && strcmp(url.proto,"https")) return _("Proxy protocol unsupported"); } return 0; } static const char *PutOrPost(xstring_c *s) { if(strcasecmp(*s,"PUT") && strcasecmp(*s,"POST")) return _("only PUT and POST values allowed"); for(char *scan=s->get_non_const(); *scan; scan++) *scan=to_ascii_upper((unsigned char)*scan); return 0; } static const char *const af_list[]= { "inet", #if INET6 "inet6", #endif 0 }; static const char *OrderValidate(xstring_c *s) { static xstring error; xstring fixed; const char * const delim="\t "; char *s1=alloca_strdup(*s); for(s1=strtok(s1,delim); s1; s1=strtok(0,delim)) { const char *const *f; for(f=af_list; *f; f++) { if(!strcasecmp(s1,*f)) break; } if(!*f) { error.setf(_("unknown address family `%s'"),s1); return error; } if(fixed) fixed.vappend(" ",s1,NULL); else fixed.set(s1); } s->set(fixed); return 0; } static const char *SortByValidate(xstring_c *s) { static const char * const valid_set[]={ "name", "name-desc", "size", "size-desc", "date", "date-desc", 0 }; return SetValidate(*s,valid_set,"mirror:order-by"); } #if USE_SSL static const char *AuthArgValidate(xstring_c *s) { for(char *i=s->get_non_const(); *i; i++) *i=to_ascii_upper(*i); const char *const valid_set[]={ "SSL", "TLS", "TLS-P", "TLS-C", 0 }; return SetValidate(*s,valid_set,"ftp:ssl-auth"); } static const char *ProtValidate(xstring_c *s) { for(char *i=s->get_non_const(); *i; i++) *i=to_ascii_upper(*i); const char *const valid_set[]={ "C", "S", "E", "P", "", 0 }; return SetValidate(*s,valid_set,"ftps:initial-prot"); } #endif static ResType lftp_vars[] = { {"ftp:abor-max-wait", "15s", ResMgr::TimeIntervalValidate,0}, {"ftp:acct", "", 0,0}, {"ftp:anon-pass", "lftp@", 0,0}, {"ftp:anon-user", "anonymous",0,0}, {"ftp:auto-sync-mode", "", ResMgr::ERegExpValidate,0}, {"ftp:auto-passive-mode", "yes", ResMgr::BoolValidate,0}, {"ftp:bind-data-socket", "yes", ResMgr::BoolValidate,0}, {"ftp:catch-size", "yes", ResMgr::BoolValidate,0}, {"ftp:charset", "", ResMgr::CharsetValidate,0}, {"ftp:client", PACKAGE "/" VERSION,0,0}, {"ftp:compressed-re", "\\.(bz2|[glrsx7]z|lzma|lz[hox]|[ai]ce|apk|ar[cj]|cab|cfs|dar|[je]ar|lha|isz|pak|rar|sitx?|t(gz|bz2|lz)|tar\\.(gz|xz|bz2|lzma)|war|zipx?|zoo|[arz0][0-9][0-9])$",ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"ftp:device-prefix", "no", ResMgr::BoolValidate,0}, {"ftp:fix-pasv-address", "yes", ResMgr::BoolValidate,0}, {"ftp:ignore-pasv-address", "no", ResMgr::BoolValidate,0}, {"ftp:fxp-force", "no", ResMgr::BoolValidate,0}, {"ftp:fxp-passive-source", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"ftp:fxp-passive-sscn", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"ftp:home", "", 0,0}, {"ftp:site" "", 0,0}, {"ftp:site-group", "", 0,0}, {"ftp:lang", "", 0,0}, {"ftp:list-empty-ok", "no", 0,0}, {"ftp:list-options", "", 0,0}, {"ftp:mode-z-level", "6", ResMgr::UNumberValidate,0}, {"ftp:nop-interval", "120", ResMgr::UNumberValidate,0}, {"ftp:passive-mode", "on", ResMgr::BoolValidate,0}, {"ftp:port-range", "full", ResMgr::RangeValidate,0}, {"ftp:port-ipv4", "", ResMgr::IPv4AddrValidate,0}, {"ftp:prefer-epsv", "no", ResMgr::BoolValidate,0}, {"ftp:proxy", "", FtpProxyValidate,0}, {"ftp:proxy-auth-type", "user", FtpProxyAuthTypeValidate,0}, {"ftp:rest-list", "no", ResMgr::BoolValidate,0}, {"ftp:rest-stor", "yes", ResMgr::BoolValidate,0}, {"ftp:timezone", "GMT", 0,0}, {"ftp:too-many-re", "(Too many|No more) connections",ResMgr::ERegExpValidate,0}, {"ftp:skey-allow", "yes", ResMgr::BoolValidate,0}, {"ftp:skey-force", "no", ResMgr::BoolValidate,0}, {"ftp:netkey-allow", "yes", ResMgr::BoolValidate,0}, #if USE_SSL {"ftp:ssl-allow", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-force", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-data", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-fxp", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-list", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-auth", "TLS", AuthArgValidate,0}, {"ftp:ssl-allow-anonymous", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-use-ccc", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-shutdown-timeout", "5", ResMgr::TimeIntervalValidate,0}, {"ftp:ssl-data-use-keys", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-copy-sid", "yes", ResMgr::BoolValidate,0}, {"ftps:initial-prot", "", ProtValidate,0}, #endif {"ftp:stat-interval", "1", ResMgr::TimeIntervalValidate,0}, {"ftp:strict-multiline", "off", ResMgr::BoolValidate,0}, {"ftp:sync-mode", "on", ResMgr::BoolValidate,0}, {"ftp:trust-feat", "no", ResMgr::BoolValidate,0}, {"ftp:use-abor", "yes", ResMgr::BoolValidate,0}, {"ftp:use-allo", "yes", ResMgr::BoolValidate,0}, {"ftp:use-feat", "yes", ResMgr::BoolValidate,0}, {"ftp:use-fxp", "yes", ResMgr::BoolValidate,0}, {"ftp:use-hftp", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mdtm", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mdtm-overloaded", "no", ResMgr::BoolValidate,0}, {"ftp:use-mlsd", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mode-z", "yes", ResMgr::BoolValidate,0}, {"ftp:use-pret", "yes", ResMgr::BoolValidate,0}, {"ftp:use-site-chmod", "yes", ResMgr::BoolValidate,0}, {"ftp:use-site-idle", "no", ResMgr::BoolValidate,0}, {"ftp:use-site-utime", "yes", ResMgr::BoolValidate,0}, {"ftp:use-site-utime2", "yes", ResMgr::BoolValidate,0}, {"ftp:use-size", "yes", ResMgr::BoolValidate,0}, {"ftp:use-stat", "yes", ResMgr::BoolValidate,0}, {"ftp:use-stat-for-list", "no", ResMgr::BoolValidate,0}, {"ftp:use-telnet-iac", "yes", ResMgr::BoolValidate,0}, {"ftp:use-tvfs", "auto", ResMgr::TriBoolValidate,0}, {"ftp:use-ip-tos", "no", ResMgr::BoolValidate,0}, {"ftp:use-utf8", "yes", ResMgr::BoolValidate,0}, {"ftp:use-quit", "yes", ResMgr::BoolValidate,0}, {"ftp:verify-address", "no", ResMgr::BoolValidate,0}, {"ftp:verify-port", "no", ResMgr::BoolValidate,0}, {"ftp:web-mode", "off", ResMgr::BoolValidate,0}, {"ftp:waiting-150-timeout", "5", ResMgr::TimeIntervalValidate,0}, #define RETRY_530 \ "too many|overloaded|try (again |back )?later|is restricted to|"\ "maximum number|number of connect|only.*session.*allowed|more connection|already connected|simultaneous login" {"ftp:retry-530", RETRY_530,ResMgr::ERegExpValidate,0}, {"ftp:retry-530-anonymous", "Login incorrect",ResMgr::ERegExpValidate,0}, {"hftp:cache", "yes", ResMgr::BoolValidate,0}, {"hftp:cache-control", "", 0,0}, {"hftp:decode", "no", ResMgr::BoolValidate,0}, {"hftp:proxy", "", HttpProxyValidate,0}, {"hftp:use-authorization", "yes", ResMgr::BoolValidate,0}, {"hftp:use-head", "yes", ResMgr::BoolValidate,0}, {"hftp:use-mkcol", "no", ResMgr::BoolValidate,0}, {"hftp:use-propfind", "no", ResMgr::BoolValidate,0}, {"hftp:use-range", "yes", ResMgr::BoolValidate,0}, {"hftp:use-allprop", "no", ResMgr::BoolValidate,0}, {"hftp:use-type", "yes", ResMgr::BoolValidate,0}, {"http:accept", "*/*", 0,0}, {"http:accept-language", "", 0,0}, {"http:accept-charset", "", 0,0}, {"http:accept-encoding", "", 0,0}, {"http:authorization", "", 0,0}, {"http:cache", "yes", ResMgr::BoolValidate,0}, {"http:cache-control", "", 0,0}, {"http:decode", "yes", ResMgr::BoolValidate,0}, {"http:proxy", "", HttpProxyValidate,0}, {"http:use-mkcol", "yes", ResMgr::BoolValidate,0}, {"http:use-propfind", "no", ResMgr::BoolValidate,0}, {"http:use-range", "yes", ResMgr::BoolValidate,0}, {"http:use-allprop", "no", ResMgr::BoolValidate,0}, {"http:user-agent", PACKAGE "/" VERSION,0,0}, {"http:cookie", "", 0,0}, {"http:set-cookies", "no", 0,0}, {"http:post-content-type", "application/x-www-form-urlencoded",0,0}, {"http:put-method", "PUT", PutOrPost,0}, {"http:put-content-type", "", 0,0}, {"http:referer", "", 0,0}, #if USE_SSL {"https:proxy", "", HttpProxyValidate,0}, #endif {"net:idle", "3m", ResMgr::TimeIntervalValidate,0}, {"net:limit-max", "0", ResMgr::UNumberValidate,0}, {"net:limit-rate", "0:0", ResMgr::UNumberPairValidate,0}, {"net:limit-total-max", "0", ResMgr::UNumberValidate,0}, {"net:limit-total-rate", "0:0", ResMgr::UNumberPairValidate,0}, {"net:max-retries", "1000", ResMgr::UNumberValidate,0}, {"net:persist-retries", "0", ResMgr::UNumberValidate,0}, {"net:no-proxy", "", 0,ResMgr::NoClosure}, {"net:reconnect-interval-base","30", ResMgr::UNumberValidate,0}, {"net:reconnect-interval-multiplier","1.5",ResMgr::FloatValidate,0}, {"net:reconnect-interval-max","600", ResMgr::UNumberValidate,0}, {"net:socket-buffer", "0", ResMgr::UNumberValidate,0}, {"net:socket-maxseg", "0", ResMgr::UNumberValidate,0}, {"net:socket-bind-ipv4", "", ResMgr::IPv4AddrValidate,0}, #if INET6 {"net:socket-bind-ipv6", "", ResMgr::IPv6AddrValidate,0}, #endif {"net:timeout", "5m", ResMgr::TimeIntervalValidate,0}, {"net:connection-limit", "0", ResMgr::UNumberValidate,0}, {"net:connection-limit-timer","5m", ResMgr::TimeIntervalValidate,0}, {"net:connection-takeover", "yes", ResMgr::BoolValidate,0}, {"mirror:sort-by", "name", SortByValidate,ResMgr::NoClosure}, {"mirror:order", "*.sfv *.sig *.md5* *.sum * */", 0,ResMgr::NoClosure}, {"mirror:parallel-directories", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:parallel-transfer-count", "0",ResMgr::UNumberValidate,0}, {"mirror:exclude-regex", "(^|/)(\\.in\\.|\\.nfs)",ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"mirror:include-regex", "", ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"mirror:use-pget-n", "0", ResMgr::UNumberValidate,0}, {"mirror:set-permissions", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:dereference", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:skip-noaccess", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:no-empty-dirs", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:require-source", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:overwrite", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"sftp:auto-confirm", "no", ResMgr::BoolValidate,0}, {"sftp:max-packets-in-flight","16", ResMgr::UNumberValidate,0}, {"sftp:protocol-version", "6", ResMgr::UNumberValidate,0}, {"sftp:size-read", "32k", ResMgr::UNumberValidate,0}, {"sftp:size-write", "32k", ResMgr::UNumberValidate,0}, {"sftp:connect-program", "ssh -a -x",0,0}, {"sftp:server-program", "sftp", 0,0}, {"sftp:charset", "", ResMgr::CharsetValidate,0}, {"sftp:use-full-path", "yes", ResMgr::BoolValidate,0}, {"file:charset", "", ResMgr::CharsetValidate,ResMgr::NoClosure}, {"file:use-lock", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"file:use-fallocate", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"dns:cache-enable", "yes", ResMgr::BoolValidate,0}, {"dns:cache-expire", "1h", ResMgr::TimeIntervalValidate,0}, {"dns:cache-size", "256", ResMgr::UNumberValidate,ResMgr::NoClosure}, {"dns:fatal-timeout", "7d", ResMgr::TimeIntervalValidate,0}, {"dns:max-retries", "1000", ResMgr::UNumberValidate,0}, {"dns:name", "", 0,ResMgr::HasClosure}, #if INET6 # define DEFAULT_ORDER "inet6 inet" #else # define DEFAULT_ORDER "inet" #endif {"dns:order", DEFAULT_ORDER, OrderValidate,0}, {"dns:SRV-query", "no", ResMgr::BoolValidate,0}, {"dns:use-fork", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, #ifdef DNSSEC_LOCAL_VALIDATION {"dns:strict-dnssec", "no", ResMgr::BoolValidate,0}, #endif {"fish:auto-confirm", "no", ResMgr::BoolValidate,0}, {"fish:shell", "/bin/sh",0,0}, {"fish:connect-program", "ssh -a -x",0,0}, {"fish:charset", "", ResMgr::CharsetValidate,0}, {"color:dir-colors", "", 0,ResMgr::NoClosure}, {"xfer:destination-directory","", 0,0}, {"xfer:verify", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:verify-command", "", ResMgr::FileExecutable,0}, {"xfer:auto-rename", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:max-log-size", "1M", ResMgr::UNumberValidate,ResMgr::NoClosure}, {"xfer:use-temp-file", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:temp-file-name", ".in.*", 0,ResMgr::NoClosure}, {"xfer:timeout", "1d", ResMgr::TimeIntervalValidate,ResMgr::NoClosure}, {"xfer:clobber", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:make-backup", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:keep-backup", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:backup-suffix", "~%Y%m%d%H%M%S~",0,ResMgr::NoClosure}, {"xfer:parallel", "1", ResMgr::UNumberValidate,ResMgr::NoClosure}, // deprecated settings {"xfer:log", "log:enabled/xfer", 0,ResMgr::AliasValidate}, {"xfer:log-file", "log:file/xfer", 0,ResMgr::AliasValidate}, {"xfer:max-log-size", "log:max-size/xfer", 0,ResMgr::AliasValidate}, #if USE_SSL {"ssl:ca-file", "", ResMgr::FileReadable,ResMgr::NoClosure}, {"ssl:crl-file", "", ResMgr::FileReadable,ResMgr::NoClosure}, {"ssl:key-file", "", ResMgr::FileReadable,0}, {"ssl:cert-file", "", ResMgr::FileReadable,0}, {"ssl:check-hostname", "yes", ResMgr::BoolValidate,0}, {"ssl:verify-certificate", "yes", ResMgr::BoolValidate,0}, {"ssl:use-sni", "yes", ResMgr::BoolValidate,0}, {"ssl:priority", "", 0,0}, # if USE_OPENSSL {"ssl:ca-path", "", ResMgr::DirReadable,ResMgr::NoClosure}, {"ssl:crl-path", "", ResMgr::DirReadable,ResMgr::NoClosure}, # endif #endif {0} }; static ResDecls lftp_vars_register(lftp_vars); #ifdef HAVE_LANGINFO_H # include #endif bool ResType::class_inited; void ResType::ClassInit() { if(class_inited) return; class_inited=true; for(ResType *scan=types_by_name->each_begin(); scan; scan=types_by_name->each_next()) { if(scan->defvalue && scan->val_valid) { xstring_c dv(scan->defvalue); const char *error=(*scan->val_valid)(&dv); if(error) fprintf(stderr,"Default value for %s is invalid: %s\n",scan->name,error); else if(strcmp(dv,scan->defvalue)) fprintf(stderr,"Default value for %s (%s) is not in canonic form: %s\n",scan->name,scan->defvalue,dv.get()); } } // inherit http proxy from environment const char *http_proxy=getenv("http_proxy"); if(http_proxy) { Set("http:proxy",0,http_proxy); Set("hftp:proxy",0,http_proxy); } #if USE_SSL const char *https_proxy=getenv("https_proxy"); if(https_proxy) Set("https:proxy",0,https_proxy); #endif const char *ftp_proxy=getenv("ftp_proxy"); if(ftp_proxy) { if(!strncmp(ftp_proxy,"ftp://",6)) Set("ftp:proxy",0,ftp_proxy); else if(!strncmp(ftp_proxy,"http://",7)) Set("hftp:proxy",0,ftp_proxy); } const char *no_proxy=getenv("no_proxy"); if(no_proxy) Set("net:no-proxy",0,no_proxy); #if INET6 // check if ipv6 is really supported int s=socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP); if(s==-1 && (errno==EINVAL #ifdef EAFNOSUPPORT || errno==EAFNOSUPPORT #endif )) { Set("dns:order",0,"inet"); } if(s!=-1) close(s); #endif // INET6 const char *module_path=getenv("LFTP_MODULE_PATH"); if(module_path) Set("module:path",0,module_path); const char *dir_colors=getenv("LS_COLORS"); if(!dir_colors) dir_colors=getenv("ZLS_COLORS"); /* zsh */ if(dir_colors) Set("color:dir-colors",0,dir_colors); const char *cs=locale_charset(); if(cs && cs[0]) Set("file:charset",0,cs); const char *time_style=getenv("TIME_STYLE"); if(time_style && *time_style) Set("cmd:time-style",0,time_style); SetDefault("xfer:verify-command",0,PKGDATADIR"/verify-file"); const char *ctx="xfer"; SetDefault("log:enabled",ctx,"yes"); SetDefault("log:show-time",ctx,"yes"); SetDefault("log:file",ctx,dir_file(get_lftp_data_dir(),"transfer_log")); }