summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/sftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/sftp.c')
-rw-r--r--crypto/openssh/sftp.c220
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, &quote, &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
OpenPOWER on IntegriCloud