void ftp_flush_reply(void) { fd_set ready; struct timeval poll; if(!ftp_connected()) return; #ifdef HAVE_LIBSSH if (ftp->session) return; #endif /* ftp_set_signal(SIGINT, SIG_IGN);*/ fprintf(stderr, "flushing replies...\r"); /* ftp_reply_timeout(10);*/ while(ftp_connected()) { poll.tv_sec = 1; poll.tv_usec = 0; FD_ZERO(&ready); int handle = sock_handle(ftp->ctrl); FD_SET(handle, &ready); if(select(handle+1, &ready, 0, 0, &poll) == 1) ftp_read_reply(); else break; } #if 0 if(ftp_loggedin()) ftp_chdir(ftp->curdir); #endif ftp_set_close_handler(); }
void ftp_flush_reply(void) { if(!ftp_connected()) return; #ifdef HAVE_LIBSSH if (ftp->session) return; #endif /* ftp_set_signal(SIGINT, SIG_IGN);*/ fprintf(stderr, "flushing replies...\r"); /* ftp_reply_timeout(10);*/ while(ftp_connected()) { if (sock_check_pending(ftp->ctrl, false) == 1) ftp_read_reply(); else break; } #if 0 if(ftp_loggedin()) ftp_chdir(ftp->curdir); #endif ftp_set_close_handler(); }
/* just gets the file SRC and store in local file DEST * doesn't parse any LIST output * returns 0 on success, else -1 */ static int do_the_get(const char *src, const char *dest, putmode_t how, unsigned opt) { char *fulldest; char *tmp; transfer_mode_t type; type = ascii_transfer(src) ? tmAscii : gvDefaultType; if(test(opt, GET_ASCII)) type = tmAscii; else if(test(opt, GET_BINARY)) type = tmBinary; tmp = getcwd(NULL, 0); if (tmp == (char *)NULL) return -1; fulldest = path_absolute(dest, tmp, 0); #if 0 && (defined(HAVE_SETPROCTITLE) || defined(linux)) if(gvUseEnvString && ftp_connected()) setproctitle("%s, get %s", ftp->url->hostname, src); #endif int r = ftp_getfile(src, dest, how, type, test(opt, GET_VERBOSE) && !gvSighupReceived && !test(opt, GET_NOHUP) ? transfer : 0); if(r == 0 && (test(opt, GET_NOHUP) || gvSighupReceived)) { fprintf(stderr, "%s [%sb of ", src, human_size(ftp->ti.size)); fprintf(stderr, "%sb]\n", human_size(ftp->ti.total_size)); } if(test(opt, GET_NOHUP)) { if(r == 0) transfer_mail_msg(_("received %s\n"), src); else transfer_mail_msg(_("failed to receive %s: %s\n"), src, ftp_getreply(false)); } free(fulldest); #if 0 && (defined(HAVE_SETPROCTITLE) || defined(linux)) if(gvUseEnvString && ftp_connected()) setproctitle("%s", ftp->url->hostname); #endif free(tmp); return r; }
void ftp_quit(void) { #ifdef HAVE_LIBSSH if (ftp_connected() && !ftp->session) #else if (ftp_connected()) #endif { ftp_reply_timeout(10); ftp_set_tmp_verbosity(vbCommand); ftp_cmd("QUIT"); } ftp_close(); }
static bool ftp_pasv(bool ipv6, unsigned char* result, unsigned short* ipv6_port) { if (!ftp->has_pasv_command) { ftp_err(_("Host doesn't support passive mode\n")); return false; } ftp_set_tmp_verbosity(vbNone); /* request passive mode */ if (!ipv6) ftp_cmd("PASV"); #ifdef HAVE_IPV6 else if (ipv6) ftp_cmd("EPSV"); #endif else return false; if (!ftp_connected()) return false; if (ftp->code != ctComplete) { ftp_err(_("Unable to enter passive mode\n")); if(ftp->code == ctError) /* no use try it again */ ftp->has_pasv_command = false; return false; } const char* e = ftp_getreply(false); while (e && !isdigit((int)*e)) e++; if (!e) { ftp_err(_("Error parsing EPSV/PASV reply: '%s'\n"), ftp_getreply(false)); return false; } if (!ipv6) { if (sscanf(e, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &result[0], &result[1], &result[2], &result[3], &result[4], &result[5]) != 6) { ftp_err(_("Error parsing PASV reply: '%s'\n"), ftp_getreply(false)); return false; } } #ifdef HAVE_IPV6 else { if (sscanf(e, "%hu", ipv6_port) != 1) { ftp_err(_("Error parsing EPSV reply: '%s'\n"), ftp_getreply(false)); return false; } } #endif return true; }
/* ** Function: time_t ftp_filetime(const char *filename) ** ** Description: User routine for attempting to obtain a remote file's ** modification time in Universal Coordinated Time (GMT). ** ** Returns; Either -1 upon failure or the time_t file modification ** time upon success. */ time_t ftp_filetime(const char *filename) { struct tm ts; if(!ftp_connected()) return -1; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_filetime(filename); #endif if(!ftp->has_mdtm_command) return -1; memset(&ts, 0, sizeof(ts)); ftp_set_tmp_verbosity(vbNone); ftp_cmd("MDTM %s", filename); if (ftp->fullcode == 202) { ftp->has_mdtm_command = false; return -1; } if (ftp->fullcode != 213) return -1; /* time is Universal Coordinated Time */ sscanf(ftp->reply, "%*s %04d%02d%02d%02d%02d%02d", &ts.tm_year, &ts.tm_mon, &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); ts.tm_year -= 1900; ts.tm_mon--; return gmt_mktime(&ts); }
/* abort routine originally from Cftp by Dieter Baron */ int ftp_abort(Socket* fp) { char buf[4096]; #ifdef HAVE_LIBSSH if(ftp->session) /* FIXME: what? */ return 0; #endif if(!ftp_connected()) return -1; ftp_set_close_handler(); if (sock_check_pending(fp, false) == 1) { ftp_trace("There is data on the control channel, won't send ABOR\n"); /* read remaining bytes from connection */ while(fp && sock_read(fp, buf, sizeof(buf)) > 0) /* LOOP */ ; return 0; } ftp->ti.interrupted = true; ftp_err(_("Waiting for remote to finish abort...\n")); ftp_trace("--> telnet interrupt\n"); if(sock_telnet_interrupt(ftp->ctrl) != 0) ftp_err("telnet interrupt: %s\n", strerror(errno)); /* ftp_cmd("ABOR") won't work here, * we must flush data between the ABOR command and ftp_read_reply() */ sock_krb_printf(ftp->ctrl, "ABOR"); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); if(ftp_get_verbosity() == vbDebug) ftp_err("--> [%s] ABOR\n", ftp->url->hostname); else ftp_trace("--> [%s] ABOR\n", ftp->url->hostname); /* read remaining bytes from connection */ while(fp && sock_read(fp, buf, sizeof(buf)) > 0) /* LOOP */ ; /* we expect a 426 or 226 reply here... */ ftp_read_reply(); if(ftp->fullcode != 426 && ftp->fullcode != 226) ftp_trace("Huh!? Expected a 426 or 226 reply\n"); /* ... and a 226 or 225 reply here, respectively */ /* FIXME: should skip this reply if prev. reply wasn't 426 or 226 ? */ ftp_read_reply(); if(ftp->fullcode != 226 && ftp->fullcode != 225) ftp_trace("Huh!? Expected a 226 or 225 reply\n"); return -1; }
void print_xterm_title(void) { char *xterm_title = expand_prompt(ftp_connected() ? (ftp_loggedin() ? gvXtermTitle3 : gvXtermTitle2) : gvXtermTitle1); print_xterm_title_string(xterm_title); free(xterm_title); }
void cmd_status(int argc, char **argv) { OPT_HELP_NEW(_("Show status."), "status [options]", NULL); maxargs(optind - 1); if(ftp_connected()) printf(_("connected to '%s'\n"), host_getoname(ftp->host)); else puts(_("not connected")); if(ftp_loggedin()) printf(_("logged in as '%s'\n"), ftp->url->username); #ifdef HAVE_KERBEROS if(ftp_connected()) sec_status(); #endif if(list_numitem(gvFtpList) > 1 || ftp_connected()) printf(_("There are totally %u connections open\n"), list_numitem(gvFtpList)); }
static int do_the_fxp(Ftp *srcftp, const char *src, Ftp *destftp, const char *dest, fxpmode_t how, unsigned opt) { transfer_mode_t type; if(test(opt, FXP_NOHUP)) fprintf(stderr, "%s\n", src); type = ascii_transfer(src) ? tmAscii : gvDefaultType; if(test(opt, FXP_ASCII)) type = tmAscii; else if(test(opt, FXP_BINARY)) type = tmBinary; #if 0 && (defined(HAVE_SETPROCTITLE) || defined(linux)) if(gvUseEnvString && ftp_connected()) setproctitle("%s, fxp %s", srcftp->url->hostname, src); #endif if(test(opt, FXP_VERBOSE)) { printf("%s\n", src); } const int r = ftp_fxpfile(srcftp, src, destftp, dest, how, type); #if 0 && (defined(HAVE_SETPROCTITLE) || defined(linux)) if(gvUseEnvString && ftp_connected()) setproctitle("%s", srcftp->url->hostname); #endif if(test(opt, FXP_NOHUP)) { if(r == 0) transfer_mail_msg(_("sent %s\n"), src); else transfer_mail_msg(_("failed to send %s: %s\n"), src, ftp_getreply(false)); } return r; }
void cmd_status(int argc, char **argv) { OPT_HELP("Show status. Usage:\n" " status [options]\n" "Options:\n" " -h, --help show this help\n"); maxargs(optind - 1); if(ftp_connected()) printf(_("connected to '%s'\n"), ftp->host->ohostname); else puts(_("not connected")); if(ftp_loggedin()) printf(_("logged in as '%s'\n"), ftp->url->username); #ifdef HAVE_KERBEROS if(ftp_connected()) sec_status(); #endif if(list_numitem(gvFtpList) > 1 || ftp_connected()) printf(_("There are totally %u connections open\n"), list_numitem(gvFtpList)); }
static int ftp_init_transfer(void) { struct sockaddr_in sa; unsigned char *a, *p; unsigned char pac[6]; if(!ftp_connected()) goto err0; if (!(ftp->data = sock_create())) { goto err0; } sock_copy(ftp->data, ftp->ctrl); if(ftp_is_passive()) { if(ftp_pasv(pac) != 0) { goto err1; } sock_getsockname(ftp->ctrl, &sa); memcpy(&sa.sin_addr, pac, (size_t)4); memcpy(&sa.sin_port, pac+4, (size_t)2); if(sock_connect_addr(ftp->data, &sa) == -1) goto err1; } else { sock_listen(ftp->data); a = (unsigned char *)&ftp->data->local_addr.sin_addr; p = (unsigned char *)&ftp->data->local_addr.sin_port; ftp_set_tmp_verbosity(vbError); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", a[0], a[1], a[2], a[3], p[0], p[1]); if(ftp->code != ctComplete) goto err1; } sock_throughput(ftp->data); return 0; err1: sock_destroy(ftp->data); err0: return -1; }
int ftp_list(const char *cmd, const char *param, FILE *fp) { if (!cmd || !fp || !ftp_connected()) return -1; #ifdef HAVE_LIBSSH if (ftp->session) return ssh_list(cmd, param, fp); #endif reset_transfer_info(); foo_hookf = NULL; #if 0 /* don't care about transfer type, binary should work well... */ ftp_type(tmAscii); #endif if (ftp_init_transfer() != 0) { ftp_err(_("transfer initialization failed")); return -1; } ftp_set_tmp_verbosity(vbNone); if (param) ftp_cmd("%s %s", cmd, param); else ftp_cmd("%s", cmd); if (ftp->code != ctPrelim) return -1; if (!sock_accept(ftp->data, "r", ftp_is_passive())) { perror("accept()"); return -1; } if (FILE_recv_ascii(ftp->data, fp) != 0) return -1; sock_destroy(ftp->data); ftp->data = NULL; ftp_read_reply(); return ftp->code == ctComplete ? 0 : -1; }
static int ftp_pasv(unsigned char result[6]) { int pa[6]; char *e; int i; if(!ftp->has_pasv_command) { ftp_err(_("Host doesn't support passive mode\n")); return -1; } ftp_set_tmp_verbosity(vbNone); /* request passive mode */ ftp_cmd("PASV"); if(!ftp_connected()) return -1; if(ftp->code != ctComplete) { ftp_err(_("Unable to enter passive mode\n")); if(ftp->code == ctError) /* no use try it again */ ftp->has_pasv_command = false; return -1; } e = ftp->reply + 4; while(!isdigit((int)*e)) e++; if(sscanf(e, "%d,%d,%d,%d,%d,%d", &pa[0], &pa[1], &pa[2], &pa[3], &pa[4], &pa[5]) != 6) { ftp_err(_("Error parsing PASV reply: '%s'\n"), ftp_getreply(false)); return -1; } for(i=0; i<6; i++) result[i] = (unsigned char)(pa[i] & 0xFF); return 0; }
/* abort routine originally from Cftp by Dieter Baron */ int ftp_abort(FILE *fp) { char buf[4096]; fd_set ready; struct timeval poll; if(ftp->ssh_pid) /* FIXME: what? */ return 0; if(!ftp_connected()) return -1; ftp_set_close_handler(); poll.tv_sec = poll.tv_usec = 0; FD_ZERO(&ready); FD_SET(ftp->ctrl->handle, &ready); if(select(ftp->ctrl->handle+1, &ready, 0, 0, &poll) == 1) { ftp_trace("There is data on the control channel, won't send ABOR\n"); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; return 0; } ftp->ti.interrupted = true; ftp_err(_("Waiting for remote to finish abort...\n")); ftp_trace("--> telnet interrupt\n"); if(sock_telnet_interrupt(ftp->ctrl) != 0) ftp_err("telnet interrupt: %s\n", strerror(errno)); /* ftp_cmd("ABOR") won't work here, * we must flush data between the ABOR command and ftp_read_reply() */ sock_krb_printf(ftp->ctrl, "ABOR"); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); if(ftp_get_verbosity() == vbDebug) ftp_err("--> [%s] ABOR\n", ftp->url->hostname); else ftp_trace("--> [%s] ABOR\n", ftp->url->hostname); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; /* we expect a 426 or 226 reply here... */ ftp_read_reply(); if(ftp->fullcode != 426 && ftp->fullcode != 226) ftp_trace("Huh!? Expected a 426 or 226 reply\n"); /* ... and a 226 or 225 reply here, respectively */ /* FIXME: should skip this reply if prev. reply wasn't 426 or 226 ? */ ftp_read_reply(); if(ftp->fullcode != 226 && ftp->fullcode != 225) ftp_trace("Huh!? Expected a 226 or 225 reply\n"); return -1; }
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; #ifdef HAVE_LIBSSH if (ftp->session) /* login authentication is performed by the ssh program */ return 0; #endif 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 && ptype < 7) { 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(host_getname(ftp->host), 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; case 7: ftp_cmd("USER %s@%s:%i", ftp->url->username, ftp->url->hostname, ftp->url->port); 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; }
static int ftp_init_transfer(void) { struct sockaddr_storage sa; unsigned char *a, *p; if(!ftp_connected()) return -1; if (!(ftp->data = sock_create())) { return -1; } sock_copy(ftp->data, ftp->ctrl); if (ftp_is_passive()) { memcpy(&sa, sock_remote_addr(ftp->ctrl), sizeof(struct sockaddr_storage)); unsigned char pac[6]; unsigned short ipv6_port; if (!ftp_pasv(sa.ss_family != AF_INET, pac, &ipv6_port)) goto err1; socklen_t len = sizeof(struct sockaddr_in); if (sa.ss_family == AF_INET) { memcpy(&((struct sockaddr_in*)&sa)->sin_addr, pac, (size_t)4); memcpy(&((struct sockaddr_in*)&sa)->sin_port, pac+4, (size_t)2); } #ifdef HAVE_IPV6 else if (sa.ss_family == AF_INET6) { ((struct sockaddr_in6*)&sa)->sin6_port = htons(ipv6_port); len = sizeof(struct sockaddr_in6); } #endif else return -1; struct sockaddr_storage tmp; memcpy(&tmp, sock_remote_addr(ftp->ctrl), sizeof(struct sockaddr_storage)); if (is_reserved((struct sockaddr*) &sa) || is_multicast((struct sockaddr*) &sa) || (is_private((struct sockaddr*) &sa) != is_private((struct sockaddr*) &tmp)) || (is_loopback((struct sockaddr*) &sa) != is_loopback((struct sockaddr*) &tmp))) { // Invalid address returned by PASV. Replace with address from control // socket. ftp_err(_("Address returned by PASV seems to be incorrect.\n")); ((struct sockaddr_in*)&sa)->sin_addr = ((struct sockaddr_in*)&tmp)->sin_addr; } if (!sock_connect_addr(ftp->data, (struct sockaddr*) &sa, len)) { perror("connect()"); goto err1; } } else { const struct sockaddr* local = sock_local_addr(ftp->data); sock_listen(ftp->data, local->sa_family); if (local->sa_family == AF_INET) { struct sockaddr_in* tmp = (struct sockaddr_in*)local; a = (unsigned char *)&tmp->sin_addr; p = (unsigned char *)&tmp->sin_port; ftp_set_tmp_verbosity(vbError); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", a[0], a[1], a[2], a[3], p[0], p[1]); } #ifdef HAVE_IPV6 else if (local->sa_family == AF_INET6) { char* addr = printable_address(local); ftp_set_tmp_verbosity(vbError); ftp_cmd("EPRT |2|%s|%u", addr, ntohs(((struct sockaddr_in6*)local)->sin6_port)); free(addr); } #endif else goto err1; if(ftp->code != ctComplete) goto err1; } sock_throughput(ftp->data); return 0; err1: sock_destroy(ftp->data); ftp->data = 0; return -1; }
static int ftp_init_transfer(void) { if (!ftp_connected()) return -1; if (!sock_dup(ftp->ctrl, &ftp->data)) return -1; if (ftp_is_passive()) { ftp_trace("Initializing passive connection.\n"); struct sockaddr_storage sa; memcpy(&sa, sock_remote_addr(ftp->ctrl), sizeof(struct sockaddr_storage)); unsigned char pac[6] = { 0 }; unsigned short ipv6_port = { 0 }; if (!ftp_pasv(sa.ss_family != AF_INET, pac, &ipv6_port)) { ftp_trace("PASV/EPSV failed.\n"); sock_destroy(ftp->data); ftp->data = NULL; return -1; } socklen_t len = sizeof(struct sockaddr_in); if (sa.ss_family == AF_INET) { memcpy(&((struct sockaddr_in*)&sa)->sin_addr, pac, (size_t)4); memcpy(&((struct sockaddr_in*)&sa)->sin_port, pac+4, (size_t)2); } #ifdef HAVE_IPV6 else if (sa.ss_family == AF_INET6) { ((struct sockaddr_in6*)&sa)->sin6_port = htons(ipv6_port); len = sizeof(struct sockaddr_in6); } #endif else { ftp_trace("Do not know how to handle family %d.\n", sa.ss_family); sock_destroy(ftp->data); ftp->data = NULL; return -1; } struct sockaddr_storage tmp; memcpy(&tmp, sock_remote_addr(ftp->ctrl), sizeof(struct sockaddr_storage)); if (is_reserved((struct sockaddr*) &sa) || is_multicast((struct sockaddr*) &sa) || (is_private((struct sockaddr*) &sa) != is_private((struct sockaddr*) &tmp)) || (is_loopback((struct sockaddr*) &sa) != is_loopback((struct sockaddr*) &tmp))) { // Invalid address returned by PASV. Replace with address from control // socket. ftp_err(_("Address returned by PASV seems to be incorrect.\n")); ((struct sockaddr_in*)&sa)->sin_addr = ((struct sockaddr_in*)&tmp)->sin_addr; } if (!sock_connect_addr(ftp->data, (struct sockaddr*) &sa, len)) { ftp_trace("Could not connect to address from PASV/EPSV.\n"); perror("connect()"); sock_destroy(ftp->data); ftp->data = NULL; return -1; } } else { ftp_trace("Initializing active connection.\n"); const struct sockaddr* local = sock_local_addr(ftp->data); sock_listen(ftp->data, local->sa_family); if (local->sa_family == AF_INET) { struct sockaddr_in* tmp = (struct sockaddr_in*)local; unsigned char* a = (unsigned char *)&tmp->sin_addr; unsigned char* p = (unsigned char *)&tmp->sin_port; ftp_set_tmp_verbosity(vbError); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", a[0], a[1], a[2], a[3], p[0], p[1]); } #ifdef HAVE_IPV6 else if (local->sa_family == AF_INET6) { char* addr = printable_address(local); ftp_set_tmp_verbosity(vbError); ftp_cmd("EPRT |2|%s|%u|", addr, ntohs(((struct sockaddr_in6*)local)->sin6_port)); free(addr); } #endif else { ftp_trace("Do not know how to handle family %d.\n", local->sa_family); sock_destroy(ftp->data); ftp->data = NULL; return -1; } if(ftp->code != ctComplete) { ftp_trace("PORT/EPRT not successful\n"); sock_destroy(ftp->data); ftp->data = NULL; return -1; } } sock_throughput(ftp->data); return 0; }
bool ftp_loggedin(void) { return (ftp_connected() && ftp->loggedin); }
static void getfiles(list *gl, unsigned int opt, const char *output) { listitem *li; rfile *fp, *lnfp; const char *opath, *ofile; char *link = 0; list_sort(gl, get_sort_func, false); li = gl->first; while(li && !get_quit) { fp = (rfile *)li->data; if(!ftp_connected()) return; if(gvSighupReceived) { if(!test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; } opath = fp->path; ofile = base_name_ptr(opath); if(strcmp(ofile, ".")==0 || strcmp(ofile, "..")==0) { transfer_nextfile(gl, &li, true); continue; } if(test(opt, GET_INTERACTIVE) && !get_batch && !gvSighupReceived) { char* sp = shortpath(opath, 42, ftp->homedir); int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Get '%s'?"), sp); free(sp); if(a == ASKNO) { transfer_nextfile(gl, &li, true); continue; } if(a == ASKCANCEL) { get_quit = true; break; } if(a == ASKALL) get_batch = true; /* else a==ASKYES */ } if(rislink(fp)) { link_to_link__duh: if(test(opt, GET_NO_DEREFERENCE)) { /* link the file, don't copy */ const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } { char *xcurdir = base_dir_xptr(opath); link = path_absolute(fp->link, xcurdir, ftp->homedir); stripslash(link); free(xcurdir); ftp_trace("found link: '%s' -> '%s'\n", opath, link); } lnfp = ftp_get_file(link); if(lnfp == 0) { /* couldn't dereference the link, try to RETR it */ ftp_trace("unable to dereference link\n"); const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } if(strncmp(opath, lnfp->path, strlen(lnfp->path)) == 0) { ftp_trace("opath == '%s', lnfp->path == '%s'\n", opath, lnfp->path); char* sp = shortpath(lnfp->path, 42, ftp->homedir); fprintf(stderr, _("%s: circular link -- skipping\n"), sp); free(sp); transfer_nextfile(gl, &li, true); continue; } fp = lnfp; if(rislink(fp)) /* found a link pointing to another link */ /* forgive me father, for I have goto'ed */ goto link_to_link__duh; } if(risdir(fp)) { if(test(opt, GET_RECURSIVE)) { char *recurs_output; char *recurs_mask; list *rgl; if((get_dir_glob_mask && fnmatch(get_dir_glob_mask, base_name_ptr(fp->path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (get_dir_rx_mask_set && regexec(&get_dir_rx_mask, base_name_ptr(fp->path), 0, 0, 0) == REG_NOMATCH) #endif ) { } else { char *q_recurs_mask; bool success = true; if(!test(opt, GET_PARENTS)) success = asprintf(&recurs_output, "%s/%s", output ? output : ".", ofile) != -1; else success = asprintf(&recurs_output, "%s", output ? output : ".") != -1; if (!success) { fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } if (asprintf(&recurs_mask, "%s/*", opath) == -1) { free(recurs_output); fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } rgl = rglob_create(); q_recurs_mask = backslash_quote(recurs_mask); rglob_glob(rgl, q_recurs_mask, true, true, get_exclude_func); free(q_recurs_mask); if(list_numitem(rgl) > 0) getfiles(rgl, opt, recurs_output); if(test(opt, GET_PRESERVE)) get_preserve_attribs(fp, recurs_output); rglob_destroy(rgl); free(recurs_output); } } else if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: omitting directory\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } if(!risreg(fp)) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: not a regular file\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); if(gvInterrupted) { gvInterrupted = false; if(li && !get_quit && ftp_connected() && !gvSighupReceived) { int a = ask(ASKYES|ASKNO, ASKYES, _("Continue transfer?")); if(a == ASKNO) { get_quit = true; break; } /* else a == ASKYES */ fprintf(stderr, _("Excellent!!!\n")); } } } }
char *expand_prompt(const char *fmt) { unsigned maxlen; char *ins, *e; bool freeins; char *tmp; if(!fmt) return 0; char* prompt = (char *)xmalloc(strlen(fmt)+1); char* cp = prompt; while(fmt && *fmt) { if(*fmt == '%') { fmt++; ins = 0; freeins = false; maxlen = (unsigned)-1; if(isdigit((int)*fmt)) { maxlen = (unsigned)atoi(fmt); while(isdigit((int)*fmt)) fmt++; } switch(*fmt) { case 'c': if (asprintf(&ins, "%u", list_numitem(gvFtpList)) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(prompt); return NULL; } freeins = true; break; case 'C': if (asprintf(&ins, "%u", connection_number()) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(prompt); return NULL; } freeins = true; break; case 'u': /* username */ ins = ftp_loggedin() ? ftp->url->username : "******"; break; case 'h': /* remote hostname (as passed to cmd_open()) */ ins = ftp_connected() ? ftp->url->hostname : "?"; break; case 'H': /* %h up to first '.' */ if(!ftp_connected()) { ins = "?"; break; } e = strchr(ftp->url->hostname, '.'); if(e) { ins = xstrndup(ftp->url->hostname, e - ftp->url->hostname); freeins = true; } else ins = ftp->url->hostname; break; case 'm': /* remote machine name (as returned from gethostbynmame) */ ins = xstrdup(ftp_connected() ? host_getoname(ftp->host) : "?"); freeins = true; break; case 'M': /* %m up to first '.' */ if(!ftp_connected()) { ins = "?"; break; } e = strchr(host_getoname(ftp->host), '.'); if(e) { ins = xstrndup(host_getoname(ftp->host), e - host_getoname(ftp->host)); } else ins = xstrdup(host_getoname(ftp->host)); freeins = true; break; case 'n': /* remote ip number */ ins = xstrdup(ftp_connected() ? host_getoname(ftp->host) : "?"); freeins = true; break; case 'w': /* current remote directory */ if(!ftp_loggedin()) { ins = "?"; break; } ins = shortpath(ftp->curdir, maxlen, 0); freeins = true; break; case 'W': /* basename(%w) */ if(!ftp_loggedin()) { ins = "?"; break; } ins = (char *)base_name_ptr(ftp->curdir); break; case '~': /* %w but homedir replaced with '~' */ if(!ftp_loggedin()) { ins = "?"; break; } ins = shortpath(ftp->curdir, maxlen, ftp->homedir); freeins = true; break; case 'l': /* current local directory */ tmp = getcwd(NULL, 0); ins = shortpath(tmp, maxlen, 0); freeins = true; free(tmp); break; case 'L': /* basename(%l) */ tmp = getcwd(NULL, 0); ins = (char *)base_name_ptr(tmp); free(tmp); break; case '%': /* percent sign */ ins = "%"; break; case '#': /* local user == root ? '#' : '$' */ ins = getuid() == 0 ? "#" : "$"; break; case '{': /* begin non-printable character string */ #ifdef HAVE_LIBREADLINE ins = "\001\001"; /* \001 + RL_PROMPT_START_IGNORE */ #endif break; case '}': /* end non-printable character string */ #ifdef HAVE_LIBREADLINE ins = "\001\002"; /* \001 + RL_PROMPT_END_IGNORE */ #endif break; case 'e': /* escape (0x1B) */ ins = "\x1B"; break; default: /* illegal format specifier */ break; } if(ins) { const size_t len = strlen(prompt) + strlen(ins) + strlen(fmt+1) + 1; char* tmp = xmalloc(len); strlcpy(tmp, prompt, len); strlcat(tmp, ins, len); cp = tmp + strlen(prompt) + strlen(ins); free(prompt); prompt = tmp; if(freeins) free(ins); } } else *cp++ = *fmt; fmt++; } unquote_escapes(prompt); return prompt; }
static void putfiles(list *gl, unsigned opt, const char *output) { struct stat sb; char *path = 0; const char *file; listitem *li; list_sort(gl, put_sort_func, false); for(li=gl->first; li && !put_quit; li=li->next) { if(!ftp_connected()) return; if(gvSighupReceived) { if(!test(opt, PUT_RESUME)) opt |= PUT_UNIQUE; opt |= PUT_FORCE; } path = (char *)li->data; file = base_name_ptr(path); if(strcmp(file, ".") == 0 || strcmp(file, "..") == 0) continue; if(test(opt, PUT_INTERACTIVE) && !put_batch) { int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Put '%s'?"), shortpath(path, 42, gvLocalHomeDir)); if(a == ASKNO) continue; if(a == ASKCANCEL) { put_quit = true; break; } if(a == ASKALL) put_batch = true; /* else a==ASKYES */ } if(stat(path, &sb) != 0) { perror(path); continue; } if(S_ISDIR(sb.st_mode)) { if(test(opt, PUT_RECURSIVE)) { char *recurs_output; char *recurs_mask; list *rgl; int r; if((put_dir_glob_mask && fnmatch(put_dir_glob_mask, base_name_ptr(path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (put_dir_rx_mask_set && regexec(&put_dir_rx_mask, base_name_ptr(path), 0, 0, 0) == REG_NOMATCH) #endif ) { /*printf("skipping %s\n", path);*/ } else { if(!test(opt, PUT_PARENTS)) { asprintf(&recurs_output, "%s/%s", output ? output : ".", file); } else recurs_output = xstrdup(output ? output : "."); asprintf(&recurs_mask, "%s/*", path); rgl = lglob_create(); r = lglob_glob(rgl, recurs_mask, true, put_exclude_func); free(recurs_mask); if(list_numitem(rgl) > 0) putfiles(rgl, opt, recurs_output); free(recurs_output); } } else fprintf(stderr, _("%s: omitting directory\n"), shortpath(path, 42, gvLocalHomeDir)); continue; } if(!S_ISREG(sb.st_mode)) { fprintf(stderr, _("%s: not a regular file\n"), shortpath(path, 42, gvLocalHomeDir)); continue; } putfile(path, &sb, opt, output); if(gvInterrupted) { gvInterrupted = false; if(li->next && !put_quit && ftp_connected() && !gvSighupReceived) { int a = ask(ASKYES|ASKNO, ASKYES, _("Continue transfer?")); if(a == ASKNO) { put_quit = true; break; } /* else a == ASKYES */ fprintf(stderr, _("Excellent!!!\n")); } } } }