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; }
int ssh_chdir(const char *path) { Attrib *aa; char *p = ftp_path_absolute(path); bool isdir = false; /* First check if this file is cached and is a directory, else we * need to stat the file to see if it really is a directory */ stripslash(p); isdir = (ftp_cache_get_directory(p) != 0); if(!isdir) { rfile *rf = ftp_cache_get_file(p); isdir = (rf && risdir(rf)); } if(!isdir) { if ((aa = ssh_stat(p)) == 0) { free(p); return -1; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { ftp_err("Can't change directory: Can't check target"); free(p); return -1; } if (!S_ISDIR(aa->perm)) { ftp_err("%s: not a directory\n", p); free(p); return -1; } } ftp_update_curdir_x(p); return 0; }
listitem *ftplist_search(const char *str) { if(isdigit((int)str[0]) && strchr(str, '.') == 0) { listitem *li; int i = 1; int n = atoi(str); if(n <= 0 || n > list_numitem(gvFtpList)) { ftp_err(_("invalid connection number: '%d'\n"), n); return 0; } for(li=gvFtpList->first; li; li=li->next, i++) { if(i == n) return li; } } else { listitem *li = list_search(gvFtpList, (listsearchfunc)switch_search, str); if(li) return li; else ftp_err(_("no such connection open: '%s'\n"), str); } return 0; }
int ssh_unlink(const char *path) { int rc = sftp_unlink(ftp->sftp_session, path); if (rc != SSH_OK && sftp_get_error(ftp->sftp_session) != SSH_FX_NO_SUCH_FILE) { ftp_err(_("Couldn't delete file: %s\n"), ssh_get_error(ftp->session)); ftp->code = ctError; ftp->fullcode = 500; return -1; } else ftp_cache_flush_mark_for(path); return 0; }
int ssh_mkdir_verb(const char *path, verbose_t verb) { char* abspath = ftp_path_absolute(path); stripslash(abspath); int rc = sftp_mkdir(ftp->sftp_session, abspath, S_IRWXU); if (rc != SSH_OK && sftp_get_error(ftp->sftp_session) != SSH_FX_FILE_ALREADY_EXISTS) { ftp_err(_("Couldn't create directory: %s\n"), ssh_get_error(ftp->session)); free(abspath); return rc; } ftp_cache_flush_mark_for(abspath); free(abspath); return 0; }
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; }
int ssh_rmdir(const char *path) { char* abspath = ftp_path_absolute(path); stripslash(abspath); int rc = sftp_rmdir(ftp->sftp_session, abspath); if (rc != SSH_OK && sftp_get_error(ftp->sftp_session) != SSH_FX_NO_SUCH_FILE) { ftp_err(_("Couldn't remove directory: %s\n"), ssh_get_error(ftp->session)); free(abspath); return rc; } ftp_cache_flush_mark(abspath); ftp_cache_flush_mark_for(abspath); free(abspath); return 0; }
int ftp_chmod(const char *path, const char *mode) { #ifdef HAVE_LIBSSH if(ftp->session) return ssh_chmod(path, mode); #endif if(ftp->has_site_chmod_command) { ftp_set_tmp_verbosity(vbNone); ftp_cmd("SITE CHMOD %s %s", mode, path); if(ftp->fullcode == 502) ftp->has_site_chmod_command = false; if(ftp->code == ctComplete) { ftp_cache_flush_mark_for(path); return 0; } } else ftp_err(_("Server doesn't support SITE CHMOD\n")); return -1; }
static int krb4_decode(void *app_data, void *buf, int len, int level) { MSG_DAT m; int e; struct krb4_data *d = app_data; if(level == prot_safe) e = krb_rd_safe(buf, len, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); else e = krb_rd_priv(buf, len, d->schedule, &d->key, (struct sockaddr_in *)REMOTE_ADDR, (struct sockaddr_in *)LOCAL_ADDR, &m); if(e){ ftp_err("krb4_decode: %s", krb_get_err_text(e)); return -1; } memmove(buf, m.app_data, m.app_length); return m.app_length; }
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 ssh_rename(const char *oldname, const char *newname) { char* on = ftp_path_absolute(oldname); char* nn = ftp_path_absolute(newname); stripslash(on); stripslash(nn); int rc = sftp_rename(ftp->sftp_session, on, nn); if (rc != SSH_OK) { ftp_err(_("Couldn't rename file '%s' to '%s': %s\n"), on, nn, ssh_get_error(ftp->session)); free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); free(on); free(nn); return 0; }
int ssh_rmdir(const char *path) { char *p; u_int status, id; p = ftp_path_absolute(path); stripslash(p); id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_RMDIR, p, strlen(p)); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't remove directory: %s\n", fx2txt(status)); free(p); return -1; } ftp_cache_flush_mark(p); ftp_cache_flush_mark_for(p); free(p); return 0; }
int ssh_rename(const char *oldname, const char *newname) { Buffer msg; u_int status, id; char *on, *nn; buffer_init(&msg); on = ftp_path_absolute(oldname); nn = ftp_path_absolute(newname); stripslash(on); stripslash(nn); /* Send rename request */ id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_RENAME); buffer_put_int(&msg, id); buffer_put_cstring(&msg, on); buffer_put_cstring(&msg, nn); ssh_cmd( &msg); buffer_free(&msg); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't rename file \"%s\" to \"%s\": %s\n", on, nn, fx2txt(status)); free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); free(on); free(nn); return 0; }
int transfer_init_nohup(const char *str) { if(!str) asprintf(&nohup_logfile, "%s/nohup/nohup.%u", gvWorkingDirectory, getpid()); else nohup_logfile = tilde_expand_home(str, gvLocalHomeDir); if(logfp) fclose(logfp); logfp = fopen(nohup_logfile, "w"); if(!logfp) { perror(nohup_logfile); free(nohup_logfile); logfp = 0; return -1; } ftp_err(_("Redirecting output to %s\n"), nohup_logfile); setbuf(logfp, 0); /* change buffering */ return 0; }
/* store a local file on remote server */ void cmd_put(int argc, char **argv) { int c, opt=PUT_VERBOSE; list *gl; char *put_output = 0; char *logfile = 0; pid_t pid; #ifdef HAVE_REGEX int ret; char put_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"nohup", no_argument, 0, 'H'}, {"interactive", no_argument, 0, 'i'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"verbose", no_argument, 0, 'v'}, {"unique", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(put_glob_mask) { free(put_glob_mask); put_glob_mask = 0; } if(put_dir_glob_mask) { free(put_dir_glob_mask); put_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = 0; } if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = 0; } #endif put_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c = getopt_long(argc, argv, "aDefHiL:no:pPqrRstvum:M:", longopts, 0)) != EOF) { switch(c) { case 'i': opt |= PUT_INTERACTIVE; break; case 'f': opt |= PUT_FORCE; break; case 'e': opt |= PUT_SKIP_EMPTY; put_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(put_dir_glob_mask); put_dir_glob_mask = xstrdup(optarg); unquote(put_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&put_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_dir_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, put_rx_errbuf); return; } else put_dir_rx_mask_set = true; break; #endif case 'o': put_output = tilde_expand_home(optarg, ftp->homedir); path_collapse(put_output); stripslash(put_output); break; case 'H': opt |= PUT_NOHUP; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 'm': /* --mask */ free(put_glob_mask); put_glob_mask = xstrdup(optarg); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = false; } ret = regcomp(&put_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optind, put_rx_errbuf); return; } else put_rx_mask_set = true; break; #endif case 'n': opt |= PUT_NEWER; break; case 'v': opt |= PUT_VERBOSE; break; case 'q': opt &= ~PUT_VERBOSE; break; case 'a': opt |= PUT_APPEND; break; case 'D': opt |= PUT_DELETE_AFTER; break; case 'u': opt |= PUT_UNIQUE; if(!ftp->has_stou_command) { fprintf(stderr, _("Remote doesn't support the STOU" " (store unique) command\n")); return; } break; case 'r': opt |= PUT_RECURSIVE; break; case 's': opt |= PUT_SKIP_EXISTING; break; case 'R': opt |= PUT_RESUME; break; case 't': opt |= PUT_TAGGED; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= PUT_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= PUT_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'p': opt |= PUT_PRESERVE; break; case 'P': opt |= PUT_PARENTS; break; case 'h': print_put_syntax();; return; case '?': return; } } if(optind>=argc && !test(opt, PUT_TAGGED)) { /* fprintf(stderr, _("missing argument, try 'put --help'"*/ /* " for more information\n"));*/ minargs(optind); return; } if(test(opt, PUT_APPEND) && test(opt, PUT_SKIP_EXISTING)) { printf("Can't use --append and --skip-existing simultaneously\n"); return; } need_connected(); need_loggedin(); gl = lglob_create(); while(optind < argc) { char *f; f = tilde_expand_home(argv[optind], gvLocalHomeDir); stripslash(f); lglob_glob(gl, f, true, put_exclude_func); optind++; } if(list_numitem(gl) == 0) { if(!test(opt, PUT_TAGGED)) { list_free(gl); return; } else if(list_numitem(gvLocalTagList) == 0) { printf(_("no tagged files\n")); list_free(gl); return; } } free(ftp->last_mkpath); ftp->last_mkpath = 0; put_quit = false; put_batch = put_owbatch = put_delbatch = test(opt, PUT_FORCE); if(test(opt, PUT_FORCE)) opt &= ~PUT_INTERACTIVE; if(put_output && !test(opt, PUT_RECURSIVE) && list_numitem(gl) + (test(opt, PUT_TAGGED) ? list_numitem(gvLocalTagList) : 0) == 1) { opt |= PUT_OUTPUT_FILE; } gvInTransfer = true; gvInterrupted = false; if(test(opt, PUT_NOHUP)) { int r = 0; pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, PUT_FORCE) && !test(opt, PUT_RESUME)) opt |= PUT_UNIQUE; opt |= PUT_FORCE; putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); gvInTransfer = false; }
/* 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(sock_sout(ftp->ctrl))) { 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; }
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; }
int ftp_open_url(url_t *urlp, bool reset_vars) { bool use_proxy; int i; if(reset_vars) ftp_reset_vars(); /* don't assume server is in ascii mode initially even if RFC says so */ ftp->prev_type = '?'; #ifdef HAVE_POSIX_SIGSETJMP if(sigsetjmp(open_timeout_jmp, 1)) #else if(setjmp(open_timeout_jmp)) #endif { ftp_close(); ftp_err(_("Connection timeout after %u seconds\n"), ftp->open_timeout); return 1; } ftp_set_signal(SIGALRM, ftp_open_handler); alarm(ftp->open_timeout); use_proxy = (proxy_type(urlp) != 0); ftp_err(_("Looking up %s... "), use_proxy ? gvProxyUrl->hostname : urlp->hostname); /* Set the default port (22) for SSH if no port is specified. We * need to do this here, 'cause host_lookup() sets it to 21 * (default port for vanilla FTP) */ if(urlp->protocol) { if(strcmp(urlp->protocol, "sftp") == 0) url_setprotocol(urlp, "ssh"); if(strcmp(urlp->protocol, "ssh") == 0 && urlp->port == -1) urlp->port = 22; /* default SSH port */ } ftp->host = host_create(use_proxy ? gvProxyUrl : urlp); if(!host_lookup(ftp->host)) { herror(host_getname(ftp->host)); alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } /* keep the value in urlp->port urlp->port = ntohs(ftp->host->port); and set it to 21 if it is -1 */ if(urlp->port == -1) { urlp->port = 21; } fprintf(stderr, "\r "); i = strlen(use_proxy ? gvProxyUrl->hostname : urlp->hostname); while(i--) fprintf(stderr, " "); fprintf(stderr, "\r"); ftp_trace("\n"); #ifdef HAVE_LIBSSH if(urlp->protocol && strcmp(urlp->protocol, "ssh") == 0) { int ret = ssh_open_url(urlp); alarm(0); return ret; } #endif if(urlp->protocol && strcmp(urlp->protocol, "ftp") != 0) { ftp_err(_("Sorry, don't know how to handle your '%s' protocol\n" "trying 'ftp' instead...\n"), urlp->protocol); url_setprotocol(urlp, 0); } if(use_proxy) { ftp_err(_("Connecting to proxy %s at port %d...\n"), host_getoname(ftp->host), urlp->port); } else { ftp_err(_("Connecting to %s at port %d...\n"), host_getoname(ftp->host), urlp->port); } ftp->ctrl = sock_create(); if (ftp->ctrl == 0) { ftp_err(_("Unable to create socket.\n")); alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } if(!sock_connect_host(ftp->ctrl, ftp->host)) { alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } sock_lowdelay(ftp->ctrl); char* ip = host_getip(ftp->host); ftp_err(_("Connected to %s ([%s]:%d).\n"), host_getoname(ftp->host), ip, urlp->port); free(ip); /* read startup message from server */ ftp_set_tmp_verbosity(vbCommand); ftp_read_reply(); if(ftp->fullcode == 120) { ftp_set_tmp_verbosity(vbCommand); ftp_read_reply(); } alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); if(!sock_connected(ftp->ctrl)) { ftp_close(); return 1; } ftp->connected = (ftp->fullcode == 220); if(ftp->connected) { void (*tracefunq)(const char *fmt, ...); url_destroy(ftp->url); ftp->url = url_clone(urlp); tracefunq = (ftp->verbosity == vbDebug ? ftp_err : ftp_trace); char* remote_addr = printable_address(sock_remote_addr(ftp->ctrl)), *local_addr = printable_address(sock_local_addr(ftp->ctrl)); tracefunq("remote address: %s\n", remote_addr); tracefunq("local address: %s\n", local_addr); free(remote_addr); free(local_addr); return 0; } else { ftp_close(); return 1; } }
/* reads one line from server into ftp->reply * returns 0 on success or -1 on failure */ static int ftp_gets(void) { int c, i=0; ftp->reply[0] = 0; if(!sock_connected(ftp->ctrl)) { ftp_err(_("No control connection\n")); return -1; } while(true) { c = sock_get(ftp->ctrl); if(c == EOF) { ftp_err(_("Server has closed control connection\n")); ftp_close(); return -1; } else if(c == 255/*IAC*/) { /* handle telnet commands */ switch(c = sock_get(ftp->ctrl)) { case 251/*WILL*/: case 252/*WONT*/: c = sock_get(ftp->ctrl); sock_printf(ftp->ctrl, "%c%c%c", 255/*IAC*/, 254/*DONT*/, c); sock_flush(ftp->ctrl); break; case 253/*DO*/: case 254/*DONT*/: c = sock_get(ftp->ctrl); sock_printf(ftp->ctrl, "%c%c%c", 255/*IAC*/, 252/*WONT*/, c); sock_flush(ftp->ctrl); break; default: break; } continue; } else if(c == '\r') { c = sock_get(ftp->ctrl); if(c == 0) c = '\r'; else if(c == '\n') { ftp->reply[i++] = (char)c; break; } else if(c == EOF) /* do nothing */ ; else { /* telnet protocol violation, hmpf... */ sock_unget(ftp->ctrl, c); continue; } } else if(c == '\n') break; if(i < MAXREPLY) ftp->reply[i++] = (char)c; } if(i >= MAXREPLY) { ftp_err(_("Reply too long (truncated)\n")); i = MAXREPLY; } ftp->reply[i] = '\0'; ftp->fullcode = atoi(ftp->reply); #ifdef SECFTP { int r = 0; switch(ftp->fullcode) { /* handle protected responses 6xx */ case 631: r = sec_read_msg(ftp->reply, prot_safe); break; case 632: r = sec_read_msg(ftp->reply, prot_private); break; case 633: r = sec_read_msg(ftp->reply, prot_confidential); break; } if(r == -1) { ftp->fullcode = 0; ftp->code = vbNone; return 0; } else ftp->fullcode = atoi(ftp->reply); } #endif strip_trailing_chars(ftp->reply, "\n\r"); ftp->code = ftp->fullcode / 100; return ftp->fullcode; }
int ssh_open_url(url_t* urlp) { ftp->session = ssh_new(); if (!ftp->session) return -1; /* set log level */ if (ftp_get_verbosity() == vbDebug) { int verbosity = SSH_LOG_PROTOCOL; ssh_options_set(ftp->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); } /* If we have ssh options from yafcrc, load them */ if (gvSSHOptions) { args_t *args = args_create(); args_init(args, 0, NULL); args_push_back(args, gvSSHOptions); int argc = 0; if (ssh_options_getopt(ftp->session, &argc, args->argv) != SSH_OK) { ftp_err(_("Failed to load SSH options from yafcrc config (ssh_options = '%s')\n"), gvSSHOptions); ssh_free(ftp->session); ftp->session = NULL; return -1; } args->argc = argc; args_destroy(args); } /* set host name */ ssh_options_set(ftp->session, SSH_OPTIONS_HOST, urlp->hostname); /* if we have port use that one */ if (urlp->port > 0) ssh_options_set(ftp->session, SSH_OPTIONS_PORT, &urlp->port); /* parse .ssh/config */ int r = ssh_options_parse_config(ftp->session, NULL); if (r != SSH_OK) { ftp_err(_("Failed to parse ssh config: %s\n"), ssh_get_error(ftp->session)); ssh_free(ftp->session); ftp->session = NULL; return r; } /* if we have username use that one */ if (urlp->username) ssh_options_set(ftp->session, SSH_OPTIONS_USER, urlp->username); /* connect to server */ r = ssh_connect(ftp->session); if (r != SSH_OK) { ftp_err(_("Couldn't initialise connection to server: %s\n"), ssh_get_error(ftp->session)); ssh_free(ftp->session); ftp->session = NULL; return r; } /* verify server */ if (verify_knownhost(ftp->session)) { ssh_disconnect(ftp->session); ssh_free(ftp->session); ftp->session = NULL; return -1; } /* authenticate user */ r = test_several_auth_methods(ftp->session, urlp); if (r != SSH_OK) { ftp_err(_("Authentication failed: %s\n"), ssh_get_error(ftp->session)); ssh_disconnect(ftp->session); ssh_free(ftp->session); ftp->session = NULL; return -1; } ftp->ssh_version = ssh_get_version(ftp->session); if (!ftp->ssh_version) { ftp_err(_("Couldn't initialise connection to server\n")); return -1; } ftp->sftp_session = sftp_new(ftp->session); if (!ftp->sftp_session) { ftp_err(_("Couldn't initialise ftp subsystem: %s\n"), ssh_get_error(ftp->session)); ssh_disconnect(ftp->session); ssh_free(ftp->session); ftp->session = NULL; return -1; } r = sftp_init(ftp->sftp_session); if (r != SSH_OK) { ftp_err(_("Couldn't initialise ftp subsystem: %s\n"), ssh_get_error(ftp->sftp_session)); sftp_free(ftp->sftp_session); ftp->sftp_session = NULL; ssh_disconnect(ftp->session); ssh_free(ftp->session); ftp->session = NULL; return r; } ftp->connected = true; ftp->loggedin = true; free(ftp->homedir); ftp->homedir = ftp_getcurdir(); url_destroy(ftp->url); ftp->url = url_clone(urlp); free(ftp->curdir); ftp->curdir = xstrdup(ftp->homedir); free(ftp->prevdir); ftp->prevdir = xstrdup(ftp->homedir); if (ftp->url->directory) ftp_chdir(ftp->url->directory); ftp_get_feat(); return 0; }
rdirectory *ftp_read_directory(const char *path) { FILE *fp = 0; rdirectory *rdir; bool is_curdir = false; bool _failed = false; char *dir; bool is_mlsd = false; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_read_directory(path); #endif dir = ftp_path_absolute(path); stripslash(dir); is_curdir = (strcmp(dir, ftp->curdir) == 0); if((fp = tmpfile()) == NULL) { /* can't create a tmpfile */ ftp_err("Unable to create temp file: %s\n", strerror(errno)); free(dir); return 0; } /* we do a "CWD" before the listing, because: we want a listing of * the directory contents, not the directory itself, and some * servers misunderstand this. If the target is a link to a * directory, we have to do this. */ if(!is_curdir) { ftp_cmd("CWD %s", dir); if(ftp->code != ctComplete) goto failed; } if(ftp->has_mlsd_command) { is_mlsd = true; #if 0 /* PureFTPd (1.0.11) doesn't recognize directory arguments * with spaces, not even quoted, it just chops the argument * string after the first space, duh... so we have to CWD to * the directory... */ char *asdf; asprintf(&asdf, "%s/", dir); /* Hack to get around issue in PureFTPd (up to version 0.98.2): * doing a 'MLSD link-to-dir' on PureFTPd closes the control * connection, however, 'MLSD link-to-dir/' works fine. */ _failed = (ftp_list("MLSD", asdf, fp) != 0); free(asdf); #else _failed = (ftp_list("MLSD", 0, fp) != 0); #endif if(_failed && ftp->code == ctError) ftp->has_mlsd_command = false; } if(!ftp->has_mlsd_command) { _failed = (ftp_list("LIST", 0, fp) != 0); is_mlsd = false; } if(!is_curdir) ftp_cmd("CWD %s", ftp->curdir); if(_failed) goto failed; rewind(fp); rdir = rdir_create(); if(rdir_parse(rdir, fp, dir, is_mlsd) != 0) { rdir_destroy(rdir); goto failed; } fclose(fp); ftp_trace("added directory '%s' to cache\n", dir); list_additem(ftp->cache, rdir); free(dir); return rdir; failed: /* forgive me father, for I have goto'ed */ if (fp) fclose(fp); free(dir); return 0; }
int ssh_list(const char *cmd, const char *param, FILE *fp) { ftp_err(_("ssh_list() not implemented yet\n")); return -1; }
rdirectory *ssh_read_directory(const char *path) { char *p = ftp_path_absolute(path); stripslash(p); sftp_dir dir = sftp_opendir(ftp->sftp_session, p); if (!dir) { free(p); return 0; } ftp_trace("*** start parsing directory listing ***\n"); rdirectory* rdir = rdir_create(); sftp_attributes attrib = NULL; while ((attrib = sftp_readdir(ftp->sftp_session, dir)) != NULL) { ftp_trace("%s\n", attrib->longname); rfile* rf = rfile_create(); rf->perm = perm2string(attrib->permissions); rf->nhl = 0; // atoi(e); if (attrib->owner) rf->owner = xstrdup(attrib->owner); if (attrib->group) rf->group = xstrdup(attrib->group); if (asprintf(&rf->path, "%s/%s", p, attrib->name) == -1) { ftp_err(_("Failed to allocate memory.\n")); sftp_closedir(dir); free(p); rdir_destroy(rdir); rfile_destroy(rf); } rf->mtime = attrib->mtime; rf->date = time_to_string(rf->mtime); rf->size = attrib->size; rfile_parse_colors(rf); rf->link = NULL; if (rislink(rf) && ftp->ssh_version > 2) rf->link = sftp_readlink(ftp->sftp_session, rf->path); list_additem(rdir->files, (void *)rf); sftp_attributes_free(attrib); } ftp_trace("*** end parsing directory listing ***\n"); if (!sftp_dir_eof(dir)) { ftp_err(_("Couldn't list directory: %s\n"), ssh_get_error(ftp->session)); sftp_closedir(dir); free(p); rdir_destroy(rdir); return NULL; } sftp_closedir(dir); rdir->path = p; ftp_trace("added directory '%s' to cache\n", p); list_additem(ftp->cache, rdir); return rdir; }
void cmd_get(int argc, char **argv) { list *gl; int opt=GET_VERBOSE, c; char *logfile = 0; pid_t pid; struct group *grp; char *get_output = 0; int stat_thresh = gvStatsThreshold; #ifdef HAVE_REGEX int ret; char get_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"chmod", required_argument, 0, 'c'}, {"chgrp", required_argument, 0, '2'}, {"no-dereference", no_argument, 0, 'd'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"interactive", no_argument, 0, 'i'}, {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"force-newer", no_argument, 0, 'F'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"nohup", no_argument, 0, 'H'}, {"verbose", no_argument, 0, 'v'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"stats", optional_argument, 0, 'S'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"unique", no_argument, 0, 'u'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(cmod) { mode_free(cmod); cmod = 0; } if(get_glob_mask) { free(get_glob_mask); get_glob_mask = 0; } if(get_dir_glob_mask) { free(get_dir_glob_mask); get_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = 0; } if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = 0; } #endif get_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c=getopt_long(argc, argv, "abHc:dDeio:fFL:tnpPvqrRsuT:m:M:", longopts, 0)) != EOF) { switch(c) { case 'a': opt |= GET_APPEND; break; case 'c': cmod = mode_compile(optarg, MODE_MASK_ALL); if(cmod == NULL) { fprintf(stderr, _("Invalid mode for --chmod: %s\n"), optarg); return; } opt |= GET_CHMOD; break; case '2': /* --chgrp */ grp = getgrnam(optarg); if(grp == 0) { fprintf(stderr, _("%s is not a valid group name\n"), optarg); return; } { int i; for(i=0; grp->gr_mem && grp->gr_mem[i]; i++) { if(strcmp(gvUsername, grp->gr_mem[i]) == 0) break; } if(!grp->gr_mem[i]) { fprintf(stderr, _("you are not a member of group %s\n"), optarg); return; } } group_change = grp->gr_gid; opt |= GET_CHGRP; break; case 'D': opt |= GET_DELETE_AFTER; break; case 'd': opt |= GET_NO_DEREFERENCE; break; case 'e': opt |= GET_SKIP_EMPTY; get_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(get_dir_glob_mask); get_dir_glob_mask = xstrdup(optarg); unquote(get_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_dir_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_dir_rx_mask_set = true; break; #endif case 'i': opt |= GET_INTERACTIVE; break; case 'f': opt |= GET_FORCE; break; case 'F': opt |= GET_FORCE_NEWER; break; case 'm': /* --mask */ free(get_glob_mask); get_glob_mask = xstrdup(optarg); unquote(get_glob_mask); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_rx_mask_set = true; break; #endif case 'o': get_output = tilde_expand_home(optarg, gvLocalHomeDir); /*stripslash(get_output);*/ unquote(get_output); break; case 'v': opt |= GET_VERBOSE; break; case 'p': opt |= GET_PRESERVE; break; case 'P': opt |= GET_PARENTS; break; case 'H': opt |= GET_NOHUP; break; case 'q': opt &= ~GET_VERBOSE; break; case 'r': opt |= GET_RECURSIVE; break; case 's': opt |= GET_SKIP_EXISTING; break; case 'S': stat_thresh = optarg ? atoi(optarg) : 0; break; case 'R': opt |= GET_RESUME; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= GET_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= GET_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'u': opt |= GET_UNIQUE; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 't': opt |= GET_TAGGED; break; case 'n': opt |= GET_NEWER; break; case 'h': print_get_syntax(); return; case '?': return; } } if(optind>=argc && !test(opt, GET_TAGGED)) { minargs(optind); return; } need_connected(); need_loggedin(); gl = rglob_create(); while(optind < argc) { stripslash(argv[optind]); if(rglob_glob(gl, argv[optind], true, true, get_exclude_func) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[optind]); optind++; } if(list_numitem(gl) == 0 && !test(opt, GET_TAGGED)) { rglob_destroy(gl); return; } if(test(opt, GET_TAGGED) && (!ftp->taglist || list_numitem(ftp->taglist)==0)) { printf(_("no tagged files\n")); if(list_numitem(gl) == 0) { rglob_destroy(gl); return; } } get_quit = false; get_batch = get_owbatch = get_delbatch = test(opt, GET_FORCE); if(test(opt, GET_FORCE)) opt &= ~GET_INTERACTIVE; if(get_output && !test(opt, GET_RECURSIVE) && list_numitem(gl) + (test(opt, GET_TAGGED) ? list_numitem(ftp->taglist) : 0) == 1) { /* if the argument to --output ends with a slash, we assume the * user wants the destination to be a directory */ char *e = strrchr(get_output, 0); if(e && e[-1] != '/') opt |= GET_OUTPUT_FILE; } stats_reset(gvStatsTransfer); gvInTransfer = true; gvInterrupted = false; if(test(opt, GET_NOHUP)) { int r = 0; pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, GET_FORCE) && !test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_output); mode_free(cmod); cmod = 0; gvInTransfer = false; stats_display(gvStatsTransfer, stat_thresh); }
static int krb4_auth(void *app_data, char *host) { int ret; char *p; int len; KTEXT_ST adat; MSG_DAT msg_data; int checksum; uint32_t cs; struct krb4_data *d = app_data; #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR; /* struct sockaddr_in *remoteaddr = (struct sockaddr_in *)REMOTE_ADDR;*/ #endif checksum = getpid(); ret = mk_auth(d, &adat, "ftp", host, checksum); if(ret == KDC_PR_UNKNOWN) ret = mk_auth(d, &adat, "rcmd", host, checksum); if(ret){ printf("%s\n", krb_get_err_text(ret)); return AUTH_CONTINUE; } #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM if (krb_get_config_bool("nat_in_use")) { struct in_addr natAddr; if (krb_get_our_ip_for_realm(krb_realmofhost(host), &natAddr) != KSUCCESS && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS) ftp_err(_("Can't get address for realm %s\n"), krb_realmofhost(host)); else { if (natAddr.s_addr != localaddr->sin_addr.s_addr) { ftp_err(_("Using NAT IP address (%s) for kerberos 4\n"), inet_ntoa(natAddr)); localaddr->sin_addr = natAddr; } } } #endif if(base64_encode(adat.dat, adat.length, &p) < 0) { ftp_err(_("Out of memory base64-encoding\n")); return AUTH_CONTINUE; } ret = ftp_cmd("ADAT %s", p); free(p); if(ftp->code != ctComplete){ ftp_err(_("Server didn't accept auth data\n")); return AUTH_ERROR; } p = strstr(ftp->reply, "ADAT="); if(!p){ ftp_err(_("Remote host didn't send adat reply\n")); return AUTH_ERROR; } p += 5; len = base64_decode(p, adat.dat); if(len < 0){ ftp_err(_("Failed to decode base64 from server\n")); return AUTH_ERROR; } adat.length = len; ret = krb_rd_safe(adat.dat, adat.length, &d->key, (struct sockaddr_in *)hisctladdr, (struct sockaddr_in *)myctladdr, &msg_data); if(ret){ ftp_err(_("Error reading reply from server: %s\n"), krb_get_err_text(ret)); return AUTH_ERROR; } krb_get_int(msg_data.app_data, &cs, 4, 0); if(cs - checksum != 1){ ftp_err(_("Bad checksum returned from server\n")); return AUTH_ERROR; } return AUTH_OK; }
/* returns: * 0 ok, remove file from list * -1 failure */ static int getfile(const rfile *fi, unsigned int opt, const char *output, const char *destname) { struct stat sb; char* dest = NULL; getmode_t how = getNormal; bool mkunique = false; int r, ret = -1; if((get_glob_mask && fnmatch(get_glob_mask, base_name_ptr(fi->path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (get_rx_mask_set && regexec(&get_rx_mask, base_name_ptr(fi->path), 0, 0, 0) == REG_NOMATCH) #endif ) { return 0; } if(!output) output = "."; if(test(opt, GET_PARENTS)) { char *apath = base_dir_xptr(fi->path); if (asprintf(&dest, "%s%s/%s", output, apath, destname) == -1) { free(apath); fprintf(stderr, _("Failed to allocate memory.\n")); return -1; } free(apath); } else { /* check if -o option is given, if GET_OUTPUT_FILE is set, we only * transfer one file and output is set to the filename. However, if * the destination already exists and is a directory, we assume * that the user meant a directory */ int dest_is_file = test(opt, GET_OUTPUT_FILE); if(stat(output, &sb) == 0) { if(S_ISDIR(sb.st_mode)) { dest_is_file = false; } } if(dest_is_file) dest = xstrdup(output); else if (asprintf(&dest, "%s/%s", output, destname) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); return -1; } } /* make sure destination directory exists */ { char *destdir = base_dir_xptr(dest); if(destdir) { bool r = make_path(destdir); if(!r) { if (errno == EEXIST) ftp_err("`%s' exists but is not a directory\n", destdir); else ftp_err("%s: %s\n", destdir, strerror(errno)); transfer_mail_msg(_("Couldn't create directory: %s\n"), destdir); free(destdir); return -1; } /* change permission and group, if requested */ if(test(opt, GET_CHMOD)) { if(stat(destdir, &sb) == 0) { mode_t m = sb.st_mode; m = mode_adjust(m, cmod); if(chmod(destdir, m) != 0) perror(destdir); } } if(test(opt, GET_CHGRP)) { if(chown(destdir, -1, group_change) != 0) perror(dest); } free(destdir); } } /* check if destination file exists */ if(stat(dest, &sb) == 0) { if(test(opt, GET_SKIP_EXISTING)) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(dest, 42, gvLocalHomeDir); fprintf(stderr, _("Local file '%s' exists, skipping...\n"), sp); stats_file(STATS_SKIP, 0); free(sp); } return 0; } if(test(opt, GET_UNIQUE)) mkunique = true; else if(test(opt, GET_APPEND)) how = getAppend; else if(test(opt, GET_NEWER)) { struct tm *fan = gmtime(&sb.st_mtime); time_t ft = ftp_filetime(fi->path, test(opt, GET_FORCE_NEWER)); sb.st_mtime = gmt_mktime(fan); ftp_trace("get -n: remote file: %s", ctime(&ft)); ftp_trace("get -n: local file: %s\n", ctime(&sb.st_mtime)); if(sb.st_mtime >= ft && ft != (time_t)-1) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(dest, 30, gvLocalHomeDir); ftp_err(_( "Local file '%s' is newer than remote, skipping...\n"), sp); stats_file(STATS_SKIP, 0); free(sp); } return 0; } } else if(!test(opt, GET_RESUME)) { if(!get_owbatch && !gvSighupReceived) { struct tm *fan = gmtime(&sb.st_mtime); time_t ft = ftp_filetime(fi->path, test(opt, GET_FORCE_NEWER)); int a; char *e; sb.st_mtime = gmt_mktime(fan); e = xstrdup(ctime(&sb.st_mtime)); char* sp = shortpath(dest, 42, gvLocalHomeDir); a = ask(ASKYES|ASKNO|ASKUNIQUE|ASKCANCEL|ASKALL|ASKRESUME, ASKRESUME, _("Local file '%s' exists\nLocal: %lld bytes, %sRemote: %lld bytes, %sOverwrite?"), sp, (unsigned long long) sb.st_size, e ? e : "unknown date\n", ftp_filesize(fi->path), ctime(&ft)); free(sp); free(e); if(a == ASKCANCEL) { get_quit = true; return 0; } else if(a == ASKNO) return 0; else if(a == ASKUNIQUE) mkunique = true; else if(a == ASKALL) { get_owbatch = true; } else if(a == ASKRESUME) opt |= GET_RESUME; /* for this file only */ /* else a == ASKYES */ } } if(test(opt, GET_RESUME)) how = getResume; } if(mkunique) { char* newdest = make_unique_filename(dest); free(dest); dest = newdest; } /* the file doesn't exist or we choosed to overwrite it, or changed dest */ if(rislink(fi) && test(opt, GET_NO_DEREFERENCE)) { /* remove any existing destination */ unlink(dest); ftp_err(_("symlinking '%s' to '%s'\n"), dest, fi->link); if(symlink(fi->link, dest) != 0) perror(dest); ret = 0; } else { r = do_the_get(fi->path, dest, how, opt); if(r == 0) { stats_file(STATS_SUCCESS, ftp->ti.total_size); ret = 0; if(test(opt, GET_PRESERVE)) get_preserve_attribs(fi, dest); if(test(opt, GET_CHMOD)) { mode_t m = rfile_getmode(fi); m = mode_adjust(m, cmod); if(chmod(dest, m) != 0) perror(dest); } if(test(opt, GET_CHGRP)) { if(chown(dest, -1, group_change) != 0) perror(dest); } if(test(opt, GET_DELETE_AFTER)) { bool dodel = false; char* sp = shortpath(fi->path, 42, ftp->homedir); if(!test(opt, GET_FORCE) && !get_delbatch && !gvSighupReceived) { int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Delete remote file '%s'?"), sp); if(a == ASKALL) { get_delbatch = true; dodel = true; } else if(a == ASKCANCEL) get_quit = true; else if(a != ASKNO) dodel = true; } else dodel = true; if(dodel) { ftp_unlink(fi->path); if(ftp->code == ctComplete) fprintf(stderr, _("%s: deleted\n"), sp); else fprintf(stderr, _("error deleting '%s': %s\n"), sp, ftp_getreply(false)); } free(sp); } } else { stats_file(STATS_FAIL, 0); ret = -1; } } free(dest); return ret; }
static int do_scp_read(ssh_scp scp, const char* infile, FILE* fp, getmode_t mode, ftp_transfer_func hookf) { time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; int rc = ssh_scp_pull_request(scp); if (rc != SSH_SCP_REQUEST_NEWFILE) { ftp_err(_("Failed to start scp download: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } size_t size = ssh_scp_request_get_size(scp); ssh_scp_accept_request(scp); /* read file */ char buffer[SSH_BUFSIZ]; int r = 0; while (size && (r = ssh_scp_read(scp, buffer, MIN(SSH_BUFSIZ, size))) != SSH_ERROR) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } errno = 0; if (fwrite(buffer, r, 1, fp) != 1) { ftp_err(_("Error while writing to file: %s\n"), strerror(errno)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } ftp->ti.size += r; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } size -= r; } if (r == SSH_ERROR) { ftp_err(_("Error while reading from file: %s\n"), ssh_get_error(ftp->session)); r = -1; } else { r = ssh_scp_pull_request(scp); if (r != SSH_SCP_REQUEST_EOF) ftp_err(_("Unexpected request: %s %lu\n"), ssh_get_error(ftp->session), size); else r = 0; } ssh_scp_close(scp); ssh_scp_free(scp); return r; }
static int do_read(const char* infile, FILE* fp, getmode_t mode, ftp_transfer_func hookf, uint64_t offset) { if (gvSSHTrySCP && !offset) { char* escaped = bash_backslash_quote(infile); /* try to set up a scp connection */ ssh_scp scp = ssh_scp_new(ftp->session, SSH_SCP_READ, escaped); free(escaped); if (scp != NULL) { int rc = ssh_scp_init(scp); if (rc == SSH_OK) return do_scp_read(scp, infile, fp, mode, hookf); ssh_scp_free(scp); } } time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; /* check if remote file is not a directory */ sftp_attributes attrib = sftp_stat(ftp->sftp_session, infile); if (!attrib) return -1; if (S_ISDIR(attrib->permissions)) { ftp_err(_("Cannot download a directory: %s\n"), infile); sftp_attributes_free(attrib); return -1; } sftp_attributes_free(attrib); /* open remote file */ sftp_file file = sftp_open(ftp->sftp_session, infile, O_RDONLY, 0); if (!file) { ftp_err(_("Cannot open file for reading: %s\n"), ssh_get_error(ftp->session)); return -1; } /* seek to offset */ int r = sftp_seek64(file, offset); if (r != SSH_OK) { ftp_err(_("Failed to seek: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; while ((nbytes = sftp_read(file, buffer, sizeof(buffer))) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } errno = 0; if (fwrite(buffer, nbytes, 1, fp) != 1) { ftp_err(_("Error while writing to file: %s\n"), strerror(errno)); ftp->ti.ioerror = true; sftp_close(file); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } } if (nbytes < 0) { ftp_err(_("Error while reading from file: %s\n"), ssh_get_error(ftp->session)); r = -1; } sftp_close(file); return r; }
static int do_scp_write(ssh_scp scp, const char* path, FILE* fp, ftp_transfer_func hookf) { time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; struct stat sb; errno = 0; if (fstat(fileno(fp), &sb) == -1) { ftp_err(_("Couldn't fstat local file: %s\n"), strerror(errno)); ssh_scp_free(scp); return -1; } int rc = ssh_scp_push_file(scp, path, sb.st_size, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (rc != SSH_OK) { ftp_err(_("Failed to start scp upload: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; errno = 0; while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } rc = ssh_scp_write(scp, buffer, nbytes); if (rc != SSH_OK) { ftp_err(_("Error while writing to file: %s\n"), ssh_get_error(ftp->session)); ssh_scp_close(scp); ssh_scp_free(scp); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } errno = 0; } if (ferror(fp)) { ftp_err(_("Failed to read from file: %s\n"), strerror(errno)); rc = -1; } ssh_scp_close(scp); ssh_scp_free(scp); return rc; }
static int do_write(const char* path, FILE* fp, ftp_transfer_func hookf, uint64_t offset) { /* try to set up a scp connection */ if (gvSSHTrySCP && !offset) { ssh_scp scp = ssh_scp_new(ftp->session, SSH_SCP_WRITE, path); if (scp != NULL) { int rc = ssh_scp_init(scp); if (rc == SSH_OK) return do_scp_write(scp, path, fp, hookf); ssh_scp_free(scp); } } time_t then = time(NULL) - 1; ftp_set_close_handler(); if (hookf) hookf(&ftp->ti); ftp->ti.begin = false; struct stat sb; errno = 0; if (fstat(fileno(fp), &sb) == -1) { ftp_err(_("Couldn't fstat local file: %s\n"), strerror(errno)); return -1; } /* open remote file */ sftp_file file = sftp_open(ftp->sftp_session, path, O_WRONLY | O_CREAT | (offset == 0u ? O_TRUNC : 0), sb.st_mode); if (!file) { ftp_err(_("Cannot open file for writing: %s\n"), ssh_get_error(ftp->session)); return -1; } /* seek to offset */ int r = sftp_seek64(file, offset); if (r != SSH_OK) { ftp_err(_("Failed to seek: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } /* read file */ char buffer[SSH_BUFSIZ]; ssize_t nbytes = 0; errno = 0; while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) > 0) { if (ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } ssize_t nwritten = sftp_write(file, buffer, nbytes); if (nwritten != nbytes) { ftp_err(_("Error while writing to file: %s\n"), ssh_get_error(ftp->session)); sftp_close(file); return -1; } ftp->ti.size += nbytes; if (hookf) { time_t now = time(NULL); if (now > then) { hookf(&ftp->ti); then = now; } } errno = 0; } if (ferror(fp)) { ftp_err(_("Failed to read from file: %s\n"), strerror(errno)); r = -1; } sftp_close(file); return r; }