📄 ftp.c.orig
字号:
} ftp_err("\n"); } else { ftp_trace("--> [%s] ", ftp->url->hostname); if(strncmp(cmd, "PASS", 4) == 0) ftp_trace("PASS ********"); else ftp_vtrace(cmd, ap); ftp_trace("\n"); }}/* sends an FTP command on the control channel * returns reply status code on success or -1 on error */int ftp_cmd(const char *cmd, ...){ va_list ap; int resp; bool recon = false; if(!sock_connected(ftp->ctrl)) { ftp_err(_("No control connection\n")); ftp->code = ctNone; ftp->fullcode = -1; return -1; } ftp_set_abort_handler(); ugly: va_start(ap, cmd); sock_krb_vprintf(ftp->ctrl, cmd, ap); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); va_end(ap); if(ferror(ftp->ctrl->sout)) { ftp_err(_("error writing command")); ftp_err(" ("); va_start(ap, cmd); vfprintf(stderr, cmd, ap); va_end(ap); va_start(ap, cmd); ftp_vtrace(cmd, ap); va_end(ap); ftp_err(")\n"); ftp->code = ctNone; ftp->fullcode = -1; return -1; } va_start(ap, cmd); ftp_print_cmd(cmd, ap); va_end(ap); resp = ftp_read_reply(); ftp_set_close_handler(); if(resp == 421) { /* server is closing control connection! */ ftp_err(_("Server closed control connection\n")); if(gvAutoReconnect && ftp_loggedin() && strcasecmp(cmd, "QUIT") != 0) { if(recon) { ftp_err(_("Reconnect failed\n")); } else { ftp_err(_("Automatic reconnect...\n")); ftp_reopen(); recon = true; goto ugly; } } else { /* ftp_close();*/ ftp->fullcode = 421; ftp->code = 4; return -1; } } return resp;}void ftp_quit(void){ if(ftp_connected() && !ftp->ssh_pid) { ftp_reply_timeout(10); ftp_set_tmp_verbosity(vbCommand); ftp_cmd("QUIT"); } ftp_close();}int ftp_get_verbosity(void){ if(ftp->tmp_verbosity != vbUnset) return ftp->tmp_verbosity; return ftp->verbosity;}void ftp_set_verbosity(int verbosity){ ftp->verbosity = verbosity; ftp->tmp_verbosity = vbUnset;}void ftp_set_tmp_verbosity(int verbosity){ if(ftp->verbosity <= vbError) ftp->tmp_verbosity = verbosity;}int get_username(url_t *url, const char *guessed_username, bool isproxy){ if(!url->username) { char *prompt, *e; if(!ftp->getuser_hook) { ftp->loggedin = false; return -1; } if(isproxy) asprintf(&prompt, _("Proxy login: ")); else if(guessed_username) asprintf(&prompt, _("login (%s): "), guessed_username); else prompt = xstrdup(_("login (anonymous): ")); e = ftp->getuser_hook(prompt); free(prompt); if(e && *e == 0) { free(e); e = 0; } if(!e) { if(guessed_username == 0) { fprintf(stderr, _("You loose\n")); ftp->loggedin = false; return -1; } url_setusername(url, guessed_username); } else { url_setusername(url, e); free(e); } } return 0;}static int get_password(url_t *url, const char *anonpass, bool isproxy){ if(!url->password) { char *e; if(url_isanon(url) && isproxy == false) { char *prompt; e = 0; if(ftp->getuser_hook) { if(anonpass && isproxy == false) asprintf(&prompt, _("password (%s): "), anonpass); else prompt = xstrdup(_("password: ")); e = ftp->getuser_hook(prompt); free(prompt); } if(!e || !*e) { free(e); e = xstrdup(anonpass); } } else { if(!ftp->getpass_hook) return -1; e = ftp->getpass_hook(isproxy ? _("Proxy password: ") : _("password: ")); } if(!e) { fprintf(stderr, _("You loose\n")); return -1; } url_setpassword(url, e); free(e); } return 0;}#ifdef SECFTPstatic const char *secext_name(const char *mech){ static struct { const char *short_name; const char *real_name; } names[] = { {"krb4", "KERBEROS_V4"}, {"krb5", "GSSAPI"}, {"gssapi", "GSSAPI"},/* {"ssl", "SSL"},*/ {"none", "none"}, {0, 0} }; int i; for(i = 0; names[i].short_name; i++) { if(strcasecmp(mech, names[i].short_name) == 0) return names[i].real_name; } return 0;}static bool mech_unsupported(const char *mech){#ifndef HAVE_KRB4 if(strcasecmp(mech, "KERBEROS_V4") == 0) return true;#endif#ifndef HAVE_KRB5 if(strcasecmp(mech, "GSSAPI") == 0) return true;#endif#ifndef USE_SSL if(strcasecmp(mech, "SSL") == 0) return true;#endif return false;}#endif /* SECFTP */int ftp_login(const char *guessed_username, const char *anonpass){ int ptype, r; static url_t *purl = 0; if(!ftp_connected()) return 1; if(!ftp->url) return -1; if(ftp->ssh_pid) /* login authentication is performed by the ssh program */ return 0; ptype = proxy_type(ftp->url); if(purl) { url_destroy(purl); purl = 0; } if(ptype > 0) purl = url_clone(gvProxyUrl); r = get_username(ftp->url, guessed_username, false); if(r != 0) return r; if(ptype > 1) { r = get_username(purl, 0, true); if(r != 0) return r; }#ifdef SECFTP ftp->sec_complete = false; ftp->data_prot = prot_clear; /* don't use secure stuff if anonymous */ if(!url_isanon(ftp->url)) { list *mechlist; /* request a protection level */ if(ftp->url->protlevel) { if(sec_request_prot(ftp->url->protlevel) != 0) ftp_err(_("Invalid protection level '%s'\n"), ftp->url->protlevel); } /* get list of mechanisms to try */ mechlist = ftp->url->mech ? ftp->url->mech : gvDefaultMechanism; if(mechlist) { listitem *li = mechlist->first; int ret = 0; for(; li; li=li->next) { const char *mech_name; mech_name = secext_name((char *)li->data); if(mech_name == 0) { ftp_err(_("unknown mechanism '%s'\n"), (char *)li->data); continue; } if(mech_unsupported(mech_name)) { ftp_err(_("Yafc was not compiled with support for %s\n"), mech_name); continue; } ret = sec_login(ftp->host->hostname, mech_name); if(ret == -1) { if(ftp->code == ctError && ftp->fullcode != 504 && ftp->fullcode != 534) url_setmech(ftp->url, "none"); } if(ret != 1) break; } } if(ftp->sec_complete) ftp_err(_("Authentication successful.\n")); else ftp_err(_("*** Using plaintext username" " and password ***\n")); }#endif if(url_isanon(ftp->url)) fprintf(stderr, _("logging in anonymously...\n")); ftp_set_tmp_verbosity(ftp->url->password ? vbError : vbCommand); switch(ptype) { case 0: default: ftp_cmd("USER %s", ftp->url->username); break; case 1: ftp_cmd("USER %s@%s", ftp->url->username, ftp->url->hostname); break; case 2: case 3: case 4: ftp_cmd("USER %s", purl->username); if(ftp->code == ctContinue) { r = get_password(purl, 0, true); if(r != 0) return 0; ftp_cmd("PASS %s", purl->password); /* FIXME: what reply code do we expect now? */ if(ftp->code < ctTransient) { if(ptype == 2) { ftp_cmd("USER %s@%s", ftp->url->username, ftp->url->hostname); } else { if(ptype == 3) ftp_cmd("SITE %s", purl->hostname); else ftp_cmd("OPEN %s", purl->hostname); if(ftp->code < ctTransient) ftp_cmd("USER %s", ftp->url->username); } } } break; case 5: ftp_cmd("USER %s@%s@%s", ftp->url->username, purl->username, ftp->url->hostname); break; case 6: ftp_cmd("USER %s@%s", purl->username, ftp->url->hostname); if(ftp->code == ctContinue) { r = get_password(purl, 0, true); if(r != 0) return 0; ftp_cmd("PASS %s", purl->password); if(ftp->code < ctTransient) ftp_cmd("USER %s", ftp->url->username); } break; } if(ftp->code == ctContinue) { ftp->loggedin = false; r = get_password(ftp->url, anonpass, false); if(r != 0) return r; if(ptype == 5) { r = get_password(purl, 0, true); if(r != 0) { url_destroy(purl); purl = 0; return 0; } } ftp_set_tmp_verbosity(vbCommand); switch(ptype) { default: case 0: case 1: case 2: case 3: case 4: case 6: ftp_cmd("PASS %s", ftp->url->password); break; case 5: ftp_cmd("PASS %s@%s", ftp->url->password, purl->password); break; } } url_destroy(purl); purl = 0; if(ftp->code > ctContinue) { if(ftp->fullcode == 530 && ftp_loggedin()) { /* this probable means '530 Already logged in' */ return 2; } ftp->loggedin = false; return 1; } if(ftp->code == ctComplete) { ftp->loggedin = true;#ifdef SECFTP /* we are logged in, now set the requested data protection level * requested from the autologin information in the config file, * if any, else uses default protection level 'clear', ie * no protection on the data channel */ if(ftp->sec_complete) { sec_set_protection_level(); fprintf(stderr, _("Data protection is %s\n"), level_to_name(ftp->data_prot)); }#endif ftp->homedir = ftp_getcurdir(); ftp->curdir = xstrdup(ftp->homedir); ftp->prevdir = xstrdup(ftp->homedir); if(ftp->url->directory) ftp_chdir(ftp->url->directory); ftp_get_feat(); return 0; } if(ftp->code == ctTransient) return 1; return -1;}bool ftp_loggedin(void){ return (ftp_connected() && ftp->loggedin);}bool ftp_connected(void){ return (ftp->connected && (sock_connected(ftp->ctrl) || ftp->ssh_pid));}char *ftp_getcurdir(void){ if(ftp->ssh_pid) return ssh_getcurdir(); ftp_set_tmp_verbosity(vbNone); ftp_cmd("PWD"); if(ftp->code == ctComplete) { char *beg, *end, *ret; beg = strchr(ftp->reply, '\"'); if(!beg) return xstrdup("CWD?"); beg++; end = strchr(beg, '\"'); if(!end) return xstrdup("CWD?"); ret = (char *)xmalloc(end-beg+1); strncpy(ret, beg, end-beg); stripslash(ret); /* path shouldn't include any quoted chars */ path_dos2unix(ret); return ret; } return xstrdup("CWD?");}void ftp_update_curdir_x(const char *p){ free(ftp->prevdir); ftp->prevdir = ftp->curdir; ftp->curdir = xstrdup(p); path_dos2unix(ftp->curdir);}static void ftp_update_curdir(void){ free(ftp->prevdir); ftp->prevdir = ftp->curdir; ftp->curdir = ftp_getcurdir();}int ftp_chdir(const char *path){ if(ftp->ssh_pid) return ssh_chdir(path); ftp_set_tmp_verbosity(vbCommand); ftp_cmd("CWD %s", path); if(ftp->code == ctComplete) { /* Now, try to be smart ;-) * Many ftp servers include the current directory in the CWD reply * try to parse it, so we don't need to issue a PWD command */ if(strncasecmp(ftp->reply, "250 Changed to ", 15) == 0) { /* this is what Troll-ftpd replies: 250 Changed to /foo/bar */ ftp_update_curdir_x(ftp->reply+15); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else if(strncasecmp(ftp->reply, "250 OK. Current directory is ", 29) == 0) { /* PureFTPd responds: "250 OK. Current directory is /foo/bar */ ftp_update_curdir_x(ftp->reply+29); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else if(strstr(ftp->reply, " is current directory") != 0) { /* WarFTPD answers: 250 "/foo/bar/" is current directory */ char *edq; char *sdq = strchr(ftp->reply, '\"'); if(sdq) { edq = strchr(sdq+1, '\"'); if(edq) { char *e = xstrndup(sdq+1, edq-sdq-1); stripslash(e); ftp_update_curdir_x(e); free(e); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } } } else if(strncasecmp(ftp->reply, "250 Directory changed to ", 25) == 0) { /* Serv-U FTP Server for WinSock */ ftp_update_curdir_x(ftp->reply + 25); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else ftp_update_curdir(); return 0; } return -1;}int ftp_cdup(void){ if(ftp->ssh_pid) return ssh_cdup(); ftp_set_tmp_verbosity(vbCommand); ftp_cmd("CDUP"); if(ftp->code == ctComplete) { ftp_update_curdir(); return 0; } return -1;}static int ftp_mkdir_verb(const char *path, verbose_t verb){ char *p; if(ftp->ssh_pid) return ssh_mkdir_verb(path, verb); p = xstrdup(path); stripslash(p); ftp_set_tmp_verbosity(verb); ftp_cmd("MKD %s", p); if(ftp->code == ctComplete) ftp_cache_flush_mark_for(p); free(p); return ftp->code == ctComplete ? 0 : -1;}int ftp_mkdir(const char *path){ return ftp_mkdir_verb(path, vbError);}int ftp_rmdir(const char *path){ char *p; if(ftp->ssh_pid) return ssh_rmdir(path); p = xstrdup(path); stripslash(p); ftp_set_tmp_verbosity(vbError); ftp_cmd("RMD %s", p); if(ftp->code == ctComplete) { ftp_cache_flush_mark(p); ftp_cache_flush_mark_for(p); } free(p); return ftp->code == ctComplete ? 0 : -1;}int ftp_unlink(const char *path){ if(ftp->ssh_pid) return ssh_unlink(path); ftp_cmd("DELE %s", path); if(ftp->code == ctComplete) { ftp_cache_flush_mark_for(path); return 0; } return -1;}int ftp_chmod(const char *path, const char *mode){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -