diff options
Diffstat (limited to 'crypto/openssh/sftp.c')
-rw-r--r-- | crypto/openssh/sftp.c | 220 |
1 files changed, 131 insertions, 89 deletions
diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index d7cbb03..d6ac4cb 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.142 2013/02/08 00:41:12 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.148 2013/07/25 00:56:52 djm Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> @@ -39,6 +39,9 @@ #ifdef HAVE_LIBGEN_H #include <libgen.h> #endif +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif #ifdef USE_LIBEDIT #include <histedit.h> #else @@ -77,12 +80,18 @@ int batchmode = 0; /* PID of ssh transport process */ static pid_t sshpid = -1; +/* Suppress diagnositic messages */ +int quiet = 0; + /* This is set to 0 if the progressmeter is not desired. */ int showprogress = 1; /* When this option is set, we always recursively download/upload directories */ int global_rflag = 0; +/* When this option is set, we resume download if possible */ +int global_aflag = 0; + /* When this option is set, the file transfers will always preserve times */ int global_pflag = 0; @@ -146,6 +155,7 @@ extern char *__progname; #define I_SYMLINK 21 #define I_VERSION 22 #define I_PROGRESS 23 +#define I_REGET 26 struct CMD { const char *c; @@ -185,6 +195,7 @@ static const struct CMD cmds[] = { { "put", I_PUT, LOCAL }, { "pwd", I_PWD, REMOTE }, { "quit", I_QUIT, NOARGS }, + { "reget", I_REGET, REMOTE }, { "rename", I_RENAME, REMOTE }, { "rm", I_RM, REMOTE }, { "rmdir", I_RMDIR, REMOTE }, @@ -216,7 +227,7 @@ cmd_interrupt(int signo) const char msg[] = "\rInterrupt \n"; int olderrno = errno; - write(STDERR_FILENO, msg, sizeof(msg) - 1); + (void)write(STDERR_FILENO, msg, sizeof(msg) - 1); interrupted = 1; errno = olderrno; } @@ -234,6 +245,7 @@ help(void) " filesystem containing 'path'\n" "exit Quit sftp\n" "get [-Ppr] remote [local] Download file\n" + "reget remote [local] Resume download file\n" "help Display this help text\n" "lcd path Change local directory to 'path'\n" "lls [ls-options [path]] Display local directory listing\n" @@ -307,7 +319,7 @@ local_do_ls(const char *args) /* XXX: quoting - rip quoting code from ftp? */ snprintf(buf, len, _PATH_LS " %s", args); local_do_shell(buf); - xfree(buf); + free(buf); } } @@ -338,15 +350,15 @@ make_absolute(char *p, char *pwd) /* Derelativise */ if (p && p[0] != '/') { abs_str = path_append(pwd, p); - xfree(p); + free(p); return(abs_str); } else return(p); } static int -parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, - int *rflag) +parse_getput_flags(const char *cmd, char **argv, int argc, + int *aflag, int *pflag, int *rflag) { extern int opterr, optind, optopt, optreset; int ch; @@ -354,9 +366,12 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, optind = optreset = 1; opterr = 0; - *rflag = *pflag = 0; - while ((ch = getopt(argc, argv, "PpRr")) != -1) { + *aflag = *rflag = *pflag = 0; + while ((ch = getopt(argc, argv, "aPpRr")) != -1) { switch (ch) { + case 'a': + *aflag = 1; + break; case 'p': case 'P': *pflag = 1; @@ -514,7 +529,7 @@ pathname_is_dir(char *pathname) static int process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, - int pflag, int rflag) + int pflag, int rflag, int resume) { char *abs_src = NULL; char *abs_dst = NULL; @@ -548,7 +563,7 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); - xfree(tmp); + free(tmp); err = -1; goto out; } @@ -564,24 +579,28 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, } else { abs_dst = xstrdup(filename); } - xfree(tmp); + free(tmp); - printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); + resume |= global_aflag; + if (!quiet && resume) + printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); + else if (!quiet && !resume) + printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { - if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, - pflag || global_pflag, 1) == -1) + if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, + pflag || global_pflag, 1, resume) == -1) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, - pflag || global_pflag) == -1) + pflag || global_pflag, resume) == -1) err = -1; } - xfree(abs_dst); + free(abs_dst); abs_dst = NULL; } out: - xfree(abs_src); + free(abs_src); globfree(&g); return(err); } @@ -633,7 +652,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); - xfree(tmp); + free(tmp); err = -1; goto out; } @@ -649,9 +668,10 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, } else { abs_dst = make_absolute(xstrdup(filename), pwd); } - xfree(tmp); + free(tmp); - printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); + if (!quiet) + printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { if (upload_dir(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, 1) == -1) @@ -664,10 +684,8 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, } out: - if (abs_dst) - xfree(abs_dst); - if (tmp_dst) - xfree(tmp_dst); + free(abs_dst); + free(tmp_dst); globfree(&g); return(err); } @@ -715,7 +733,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) /* Add any subpath that also needs to be counted */ tmp = path_strip(path, strip_path); m += strlen(tmp); - xfree(tmp); + free(tmp); if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; @@ -741,7 +759,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) tmp = path_append(path, d[n]->filename); fname = path_strip(tmp, strip_path); - xfree(tmp); + free(tmp); if (lflag & LS_LONG_VIEW) { if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { @@ -753,7 +771,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS)); printf("%s\n", lname); - xfree(lname); + free(lname); } else printf("%s\n", d[n]->longname); } else { @@ -765,7 +783,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) c++; } - xfree(fname); + free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) @@ -835,7 +853,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, lname = ls_file(fname, g.gl_statv[i], 1, (lflag & LS_SI_UNITS)); printf("%s\n", lname); - xfree(lname); + free(lname); } else { printf("%-*s", colspace, fname); if (c >= columns) { @@ -844,7 +862,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, } else c++; } - xfree(fname); + free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) @@ -1113,8 +1131,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, } static int -parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, - int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) +parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, + int *pflag, int *rflag, int *sflag, unsigned long *n_arg, + char **path1, char **path2) { const char *cmd, *cp = *cpp; char *cp2, **argv; @@ -1158,14 +1177,15 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, } /* Get arguments and parse flags */ - *lflag = *pflag = *rflag = *hflag = *n_arg = 0; + *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0; *path1 = *path2 = NULL; optidx = 1; switch (cmdnum) { case I_GET: + case I_REGET: case I_PUT: if ((optidx = parse_getput_flags(cmd, argv, argc, - pflag, rflag)) == -1) + aflag, pflag, rflag)) == -1) return -1; /* Get first pathname (mandatory) */ if (argc - optidx < 1) { @@ -1180,6 +1200,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, /* Destination is not globbed */ undo_glob_escape(*path2); } + if (*aflag && cmdnum == I_PUT) { + /* XXX implement resume for uploads */ + error("Resume is not supported for uploads"); + return -1; + } break; case I_LINK: if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) @@ -1288,7 +1313,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, int err_abort) { char *path1, *path2, *tmp; - int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0; + int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; + int rflag = 0, sflag = 0; int cmdnum, i; unsigned long n_arg = 0; Attrib a, *aa; @@ -1297,9 +1323,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, glob_t g; path1 = path2 = NULL; - cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, - &sflag, &n_arg, &path1, &path2); - + cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag, + &rflag, &sflag, &n_arg, &path1, &path2); if (iflag != 0) err_abort = 0; @@ -1314,8 +1339,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, /* Unrecognized command */ err = -1; break; + case I_REGET: + aflag = 1; + /* FALLTHROUGH */ case I_GET: - err = process_get(conn, path1, path2, *pwd, pflag, rflag); + err = process_get(conn, path1, path2, *pwd, pflag, + rflag, aflag); break; case I_PUT: err = process_put(conn, path1, path2, *pwd, pflag, rflag); @@ -1328,8 +1357,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, case I_SYMLINK: sflag = 1; case I_LINK: - if (!sflag) - path1 = make_absolute(path1, *pwd); + path1 = make_absolute(path1, *pwd); path2 = make_absolute(path2, *pwd); err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); break; @@ -1337,7 +1365,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { - printf("Removing %s\n", g.gl_pathv[i]); + if (!quiet) + printf("Removing %s\n", g.gl_pathv[i]); err = do_rm(conn, g.gl_pathv[i]); if (err != 0 && err_abort) break; @@ -1361,24 +1390,24 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, break; } if ((aa = do_stat(conn, tmp, 0)) == NULL) { - xfree(tmp); + free(tmp); err = 1; break; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); - xfree(tmp); + free(tmp); err = 1; break; } if (!S_ISDIR(aa->perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); - xfree(tmp); + free(tmp); err = 1; break; } - xfree(*pwd); + free(*pwd); *pwd = tmp; break; case I_LS: @@ -1433,7 +1462,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, a.perm = n_arg; remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { - printf("Changing mode on %s\n", g.gl_pathv[i]); + if (!quiet) + printf("Changing mode on %s\n", g.gl_pathv[i]); err = do_setstat(conn, g.gl_pathv[i], &a); if (err != 0 && err_abort) break; @@ -1462,10 +1492,14 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, } aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; if (cmdnum == I_CHOWN) { - printf("Changing owner on %s\n", g.gl_pathv[i]); + if (!quiet) + printf("Changing owner on %s\n", + g.gl_pathv[i]); aa->uid = n_arg; } else { - printf("Changing group on %s\n", g.gl_pathv[i]); + if (!quiet) + printf("Changing group on %s\n", + g.gl_pathv[i]); aa->gid = n_arg; } err = do_setstat(conn, g.gl_pathv[i], aa); @@ -1506,10 +1540,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, if (g.gl_pathc) globfree(&g); - if (path1) - xfree(path1); - if (path2) - xfree(path2); + free(path1); + free(path2); /* If an unignored error occurs in batch mode we should abort. */ if (err_abort && err != 0) @@ -1619,8 +1651,8 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, complete_display(list, 0); for (y = 0; list[y] != NULL; y++) - xfree(list[y]); - xfree(list); + free(list[y]); + free(list); return count; } @@ -1633,7 +1665,7 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, list[count] = NULL; if (count == 0) { - xfree(list); + free(list); return 0; } @@ -1643,8 +1675,8 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, complete_display(list, 0); for (y = 0; list[y]; y++) - xfree(list[y]); - xfree(list); + free(list[y]); + free(list); if (tmp != NULL) { tmplen = strlen(tmp); @@ -1665,7 +1697,7 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, if (y > 0 && el_insertstr(el, argterm) == -1) fatal("el_insertstr failed."); } - xfree(tmp); + free(tmp); } return count; @@ -1696,8 +1728,9 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, char *file, int remote, int lastarg, char quote, int terminated) { glob_t g; - char *tmp, *tmp2, ins[3]; + char *tmp, *tmp2, ins[8]; u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; + int clen; const LineInfo *lf; /* Glob from "file" location */ @@ -1729,7 +1762,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, if (tmp[tmplen] == '/') pwdlen = tmplen + 1; /* track last seen '/' */ } - xfree(tmp); + free(tmp); if (g.gl_matchc == 0) goto out; @@ -1744,7 +1777,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); tmp = path_strip(tmp2, isabs ? NULL : remote_path); - xfree(tmp2); + free(tmp2); if (tmp == NULL) goto out; @@ -1766,10 +1799,13 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, tmp2 = tmp + filelen - cesc; len = strlen(tmp2); /* quote argument on way out */ - for (i = 0; i < len; i++) { + for (i = 0; i < len; i += clen) { + if ((clen = mblen(tmp2 + i, len - i)) < 0 || + (size_t)clen > sizeof(ins) - 2) + fatal("invalid multibyte character"); ins[0] = '\\'; - ins[1] = tmp2[i]; - ins[2] = '\0'; + memcpy(ins + 1, tmp2 + i, clen); + ins[clen + 1] = '\0'; switch (tmp2[i]) { case '\'': case '"': @@ -1806,7 +1842,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, if (i > 0 && el_insertstr(el, ins) == -1) fatal("el_insertstr failed."); } - xfree(tmp); + free(tmp); out: globfree(&g); @@ -1818,7 +1854,8 @@ static unsigned char complete(EditLine *el, int ch) { char **argv, *line, quote; - u_int argc, carg, cursor, len, terminated, ret = CC_ERROR; + int argc, carg; + u_int cursor, len, terminated, ret = CC_ERROR; const LineInfo *lf; struct complete_ctx *complete_ctx; @@ -1832,7 +1869,7 @@ complete(EditLine *el, int ch) memcpy(line, lf->buffer, cursor); line[cursor] = '\0'; argv = makeargv(line, &carg, 1, "e, &terminated); - xfree(line); + free(line); /* Get all the arguments on the line */ len = lf->lastchar - lf->buffer; @@ -1844,7 +1881,7 @@ complete(EditLine *el, int ch) /* Ensure cursor is at EOL or a argument boundary */ if (line[cursor] != ' ' && line[cursor] != '\0' && line[cursor] != '\n') { - xfree(line); + free(line); return ret; } @@ -1872,7 +1909,7 @@ complete(EditLine *el, int ch) ret = CC_REDISPLAY; } - xfree(line); + free(line); return ret; } #endif /* USE_LIBEDIT */ @@ -1924,31 +1961,30 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) dir = make_absolute(dir, remote_path); if (remote_is_dir(conn, dir) && file2 == NULL) { - printf("Changing to: %s\n", dir); + if (!quiet) + printf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); if (parse_dispatch_command(conn, cmd, &remote_path, 1) != 0) { - xfree(dir); - xfree(remote_path); - xfree(conn); + free(dir); + free(remote_path); + free(conn); return (-1); } } else { /* XXX this is wrong wrt quoting */ - if (file2 == NULL) - snprintf(cmd, sizeof cmd, "get %s", dir); - else - snprintf(cmd, sizeof cmd, "get %s %s", dir, - file2); - + snprintf(cmd, sizeof cmd, "get%s %s%s%s", + global_aflag ? " -a" : "", dir, + file2 == NULL ? "" : " ", + file2 == NULL ? "" : file2); err = parse_dispatch_command(conn, cmd, &remote_path, 1); - xfree(dir); - xfree(remote_path); - xfree(conn); + free(dir); + free(remote_path); + free(conn); return (err); } - xfree(dir); + free(dir); } setlinebuf(stdout); @@ -2006,8 +2042,8 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) if (err != 0) break; } - xfree(remote_path); - xfree(conn); + free(remote_path); + free(conn); #ifdef USE_LIBEDIT if (el != NULL) @@ -2114,6 +2150,7 @@ main(int argc, char **argv) /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); + setlocale(LC_CTYPE, ""); __progname = ssh_get_progname(argv[0]); memset(&args, '\0', sizeof(args)); @@ -2128,7 +2165,7 @@ main(int argc, char **argv) infile = stdin; while ((ch = getopt(argc, argv, - "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { + "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { switch (ch) { /* Passed through to ssh(1) */ case '4': @@ -2145,6 +2182,8 @@ main(int argc, char **argv) addargs(&args, "%s", optarg); break; case 'q': + ll = SYSLOG_LEVEL_ERROR; + quiet = 1; showprogress = 0; addargs(&args, "-%c", ch); break; @@ -2166,6 +2205,9 @@ main(int argc, char **argv) case '2': sshver = 2; break; + case 'a': + global_aflag = 1; + break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') @@ -2180,7 +2222,7 @@ main(int argc, char **argv) (infile = fopen(optarg, "r")) == NULL) fatal("%s (%s).", strerror(errno), optarg); showprogress = 0; - batchmode = 1; + quiet = batchmode = 1; addargs(&args, "-obatchmode yes"); break; case 'p': @@ -2277,7 +2319,7 @@ main(int argc, char **argv) if (conn == NULL) fatal("Couldn't initialise connection to server"); - if (!batchmode) { + if (!quiet) { if (sftp_direct == NULL) fprintf(stderr, "Connected to %s.\n", host); else |