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; }
int Ftp::login(const char* user, const char* password) { int ret; // get all the welcome message ret = ftp_cmd(); switch (ret) { case 220: break; default: return ret; } ret = ftp_cmd("USER", user == NULL ? "anonymous" : user); switch (ret) { case 230: return 0; case 331: break; default: return ret; } ret = ftp_cmd("PASS", password == NULL ? "myget@myget" : password); switch (ret) { case 230: return 0; default: return ret; } };
int ftp_rename(const char *oldname, const char *newname) { char *on; char *nn; #ifdef HAVE_LIBSSH if (ftp->session) return ssh_rename(oldname, newname); #endif on = xstrdup(oldname); stripslash(on); ftp_cmd("RNFR %s", on); if(ftp->code != ctContinue) { free(on); return -1; } nn = xstrdup(newname); stripslash(nn); ftp_cmd("RNTO %s", nn); if(ftp->code != ctComplete) { free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); return 0; }
static int ftp_init_receive(const char *path, transfer_mode_t mode, ftp_transfer_func hookf) { long rp = ftp->restart_offset; char *e; ftp->restart_offset = 0L; foo_hookf = hookf; reset_transfer_info(); if(ftp_init_transfer() != 0) return -1; ftp_type(mode); if(rp > 0) { /* fp is assumed to be fseek'd already */ ftp_cmd("REST %ld", rp); if(ftp->code != ctContinue) return -1; ftp->ti.size = rp; ftp->ti.restart_size = rp; } ftp_cmd("RETR %s", path); if(ftp->code != ctPrelim) return -1; if(!sock_accept(ftp->data, "r", ftp_is_passive())) { ftp_err(_("data connection not accepted\n")); return -1; } /* try to get the total file size */ { /* see if we have cached this directory/file */ rfile *f = ftp_cache_get_file(path); if(f) ftp->ti.total_size = f->size; else { /* try to figure out file size from RETR reply * Opening BINARY mode data connection for foo.mp3 (14429793 bytes) * ^^^^^^^^ aha! * * note: this might not be the _total_ filesize if we are RESTarting */ e = strstr(ftp->reply, " bytes"); if(e != 0) { while((e > ftp->reply) && isdigit((int)e[-1])) e--; ftp->ti.total_size = strtoul(e,NULL,10); } /* else we don't bother */ } } return 0; }
int Ftp::pasv(int *port) { int ret; char *ptr; *port = 0; /********************************** * RFC2428 * ipv4: * <=PASV * =>227 xxxx(h1,h2,h3,h4,p1,p2) * ipv6: * normal: * <=EPSV * extension: * <=EPSV 1 //use ipv4 connection * <=EPSV 2 //use ipv6 connection * =>229 xxxx(|||6446|) */ if (remoteAddr.ai_family == AF_INET) { // ipv4 ret = ftp_cmd("PASV"); switch (ret) { case 227: break; default: return ret; } // xxxx(h1,h2,h3,h4,p1,p2) if ((ptr=strrchr(stateLine, ',')) == NULL) return -1; *port = atoi(ptr+1); do { ptr--; } while (ptr != stateLine && ISDIGIT(*ptr)); if (ptr == stateLine) return -1; *port += atoi(ptr+1)<<8; } else if (remoteAddr.ai_family == AF_INET6) { ret = ftp_cmd("EPSV", "2"); switch (ret) { case 229: break; default: return ret; } // xxxx(|||6446|) if ((ptr=strrchr(stateLine, '|')) == NULL) return -1; do { ptr--; } while (ptr != stateLine && ISDIGIT(*ptr)); if (ptr == stateLine) return -1; *port = atoi(ptr+1); } else { return -1; } return 0; };
/* * Set transfer mode and data type */ static int ftp_mode_type(conn_t *conn, int mode, int type) { int e; switch (mode) { case 0: case 's': mode = 'S'; case 'S': break; default: return (FTP_PROTOCOL_ERROR); } if ((e = ftp_cmd(conn, "MODE %c\r\n", mode)) != FTP_OK) { if (mode == 'S') { /* * Stream mode is supposed to be the default - so * much so that some servers not only do not * support any other mode, but do not support the * MODE command at all. * * If "MODE S" fails, it is unlikely that we * previously succeeded in setting a different * mode. Therefore, we simply hope that the * server is already in the correct mode, and * silently ignore the failure. */ } else { return (e); } } switch (type) { case 0: case 'i': type = 'I'; case 'I': break; case 'a': type = 'A'; case 'A': break; case 'd': type = 'D'; case 'D': /* can't handle yet */ default: return (FTP_PROTOCOL_ERROR); } if ((e = ftp_cmd(conn, "TYPE %c\r\n", type)) != FTP_OK) return (e); return (FTP_OK); }
int ftp_help(const char *arg) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_help(arg); #endif ftp_set_tmp_verbosity(vbCommand); if(arg) ftp_cmd("HELP %s", arg); else ftp_cmd("HELP"); return ftp->code == ctComplete ? 0 : -1; }
int Ftp::size(const char *file, off_t *size) { int ret; char *ptr; if (!file) return -1; ret = ftp_cmd("SIZE", file); switch (ret) { case 213: break; default: return ret; } *size = 0; ptr = stateLine; while (*ptr == ' ') ptr++; while (ISDIGIT(*ptr)) { *size *= 10; *size += *ptr -= '0'; ptr++; } return 0; };
int Ftp::port(int port) { int ret; char buffer[128]; char addr[INET6_ADDRSTRLEN]; char *ptr; /************************************ * RFC2428 * ipv4: * <=PORT 10,20,12,66,port>>8,port&0xff * <=EPRT |1|132.235.1.2|6275| * ipv6: * <=EPRT |2|IPv6.ascii|PORT.ascii| * =>200 xxx */ if (localAddr.ai_family == AF_INET) { if (localAddr.get_addr(addr, INET_ADDRSTRLEN) < 0) return -1; ptr = addr; while (*ptr) { if (*ptr == '.') *ptr = ','; ptr++; } snprintf(buffer, sizeof(buffer), "%s,%d,%d", addr, port>>8, port&0xff); ret = ftp_cmd("PORT", buffer); } else if (localAddr.ai_family == AF_INET6) {
/* * Close the FTP coprocess' current connection, but * keep the process itself alive. */ void ftp_stop(void) { #if defined(__svr4__) && defined(__sun__) char env[BUFSIZ]; #endif const char *tmp1, *tmp2; if (!ftp_started) return; tmp1=getenv(PKG_FTPIO_COMMAND); tmp2=getenv(PKG_FTPIO_ANSWER); /* (Only) the last one closes the link */ if (tmp1 != NULL && tmp2 != NULL) { if (needclose) ftp_cmd("close\n", "\n(221 .*|Not connected.)\n"); (void) close(ftpio.command); (void) close(ftpio.answer); } #if defined(__svr4__) && defined(__sun__) (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_COMMAND); putenv(env); (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_ANSWER); putenv(env); #else unsetenv(PKG_FTPIO_COMMAND); unsetenv(PKG_FTPIO_ANSWER); #endif }
char *ftp_getcurdir(void) { #ifdef HAVE_LIBSSH if (ftp->session) return ssh_getcurdir(); #endif 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?"); }
/* ** 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); }
unsigned long long ftp_filesize(const char *path) { unsigned long long ret; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_filesize(path); #endif if(!ftp->has_size_command) return -1; if(ftp_type(tmBinary) != 0) return -1; ftp_set_tmp_verbosity(vbError); ftp_cmd("SIZE %s", path); if(ftp->fullcode == 502) { ftp->has_size_command = false; return -1; } if(ftp->code == ctComplete) { sscanf(ftp->reply, "%*s %llu", &ret); return ret; } 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; }
/* return values: * 0 - success * 1 - failed, try another mechanism * -1 - failed, security extensions not supported */ int sec_login(const char *host, const char *mech_to_try) { int ret; struct sec_client_mech **m; void *tmp; /* shut up all messages this will produce (they are usually not very user friendly) */ ftp_set_tmp_verbosity(vbError); if(!mech_to_try || strcasecmp(mech_to_try, "none") == 0) return 0; m = find_mech(mech_to_try); if(!m) return 1; tmp = realloc(ftp->app_data, (*m)->size); if (tmp == NULL) { ftp_err(_("realloc %zu failed"), (*m)->size); return -1; } ftp->app_data = tmp; if ((*m)->init && (*(*m)->init) (ftp->app_data) != 0) { printf(_("Skipping %s...\n"), (*m)->name); return 1; } printf(_("Trying %s...\n"), (*m)->name); ret = ftp_cmd("AUTH %s", (*m)->name); if (ftp->code != ctContinue) { if (ret == 504) { printf(_("%s is not supported by the server.\n"), (*m)->name); } else if (ret == 534) { printf(_("%s rejected as security mechanism.\n"), (*m)->name); } else if (ftp->code == ctError) { printf(_("The server doesn't support the FTP " "security extensions.\n")); return -1; } return 1; } ret = (*(*m)->auth) (ftp->app_data, host); if (ret == AUTH_CONTINUE) return 1; else if (ret != AUTH_OK) { /* mechanism is supposed to output error string */ return -1; } ftp->mech = *m; ftp->sec_complete = 1; ftp->command_prot = prot_safe; return *m == NULL; }
int Ftp::cwd(const char* dir) { int ret; ret = ftp_cmd("CWD", dir ? dir : "/"); switch (ret) { case 250: return 0; default: return ret; } };
int ftp_noop(void) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_noop(); #endif ftp_set_tmp_verbosity(vbCommand); ftp_cmd("NOOP"); return ftp->code == ctComplete ? 0 : -1; }
int Ftp::type(const char* type) { int ret; if (!type) return -1; ret = ftp_cmd("TYPE", type); switch (ret) { case 200: return 0; default: return ret; } };
void ftp_pwd(void) { #ifdef HAVE_LIBSSH if (ftp->session) { ssh_pwd(); return; } #endif ftp_set_tmp_verbosity(vbCommand); ftp_cmd("PWD"); }
int ftp_idle(const char *idletime) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_idle(idletime); #endif if(!ftp->has_site_idle_command) { ftp_err(_("Server doesn't support SITE IDLE\n")); return -1; } ftp_set_tmp_verbosity(vbCommand); if(idletime) ftp_cmd("SITE IDLE %s", idletime); else ftp_cmd("SITE IDLE"); if(ftp->fullcode == 502) ftp->has_site_idle_command = false; return ftp->code == ctComplete ? 0 : -1; }
int ftp_unlink(const char *path) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_unlink(path); #endif ftp_cmd("DELE %s", path); if(ftp->code == ctComplete) { ftp_cache_flush_mark_for(path); return 0; } return -1; }
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(); }
int Ftp::rest(off_t offset) { int ret; if (offset < 0) return -1; char buffer[64]; snprintf(buffer, sizeof(buffer), "%lu", offset); ret = ftp_cmd("REST", buffer); switch (ret) { case 350: return 0; default: return ret; } };
int ftp_chdir(const char *path) { #ifdef HAVE_LIBSSH if (ftp->session) return ssh_chdir(path); #endif 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) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_cdup(); #endif ftp_set_tmp_verbosity(vbCommand); ftp_cmd("CDUP"); if(ftp->code == ctComplete) { ftp_update_curdir(); return 0; } return -1; }
static int sec_prot_internal(int level) { char *p; unsigned int s = 1048576; ftp_set_tmp_verbosity(vbError); if (!ftp->sec_complete) { ftp_err(_("No security data exchange has taken place.\n")); return -1; } if (level) { ftp_cmd("PBSZ %u", s); if (ftp->code != ctComplete) { ftp_err(_("Failed to set protection buffer size.\n")); return -1; } ftp->buffer_size = s; p = strstr(ftp->reply, "PBSZ="); if (p) sscanf(p, "PBSZ=%u", &s); if (s < ftp->buffer_size) ftp->buffer_size = s; } ftp_cmd("PROT %c", level["CSEP"]); /* XXX :-) */ if (ftp->code != ctComplete) { ftp_err(_("Failed to set protection level.\n")); return -1; } ftp->data_prot = (enum protection_level)level; url_setprotlevel(ftp->url, level_to_name(ftp->data_prot)); return 0; }
void cmd_rstatus(int argc, char **argv) { OPT_HELP_NEW(_("Show status of remote host."), "rstatus [options]", NULL); maxargs(optind - 1); need_connected(); #ifdef HAVE_LIBSSH if(ftp->session) { printf("No status for SSH connection\n"); return; } #endif ftp_set_tmp_verbosity(vbCommand); ftp_cmd("STAT"); }
int ftp_type(transfer_mode_t type) { if(ftp->ssh_pid) /* FIXME: is this relevant for ssh ? */ return 0; if(type == tmCurrent) return 0; if(ftp->prev_type != type) { ftp_cmd("TYPE %c", type == tmAscii ? 'A' : 'I'); if(ftp->code != ctComplete) return -1; ftp->prev_type = type; } return 0; }
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; }
void cmd_site(int argc, char **argv) { char *e; minargs_nohelp(1); need_connected(); if(ftp->ssh_pid) { printf("SITE commands not available in SSH connections\n"); return; } e = args_cat(argc, argv, 1); ftp_set_tmp_verbosity(vbCommand); ftp_cmd("SITE %s", e); free(e); }