version 1.1.1.17, 2018/08/26 07:41:00 |
version 1.1.1.18, 2019/04/20 17:13:53 |
|
|
/* $OpenBSD: sftp.c,v 1.185 2018/04/26 14:47:03 bluhm Exp $ */ |
/* $OpenBSD: sftp.c,v 1.190 2019/01/21 22:50:42 tb Exp $ */ |
/* |
/* |
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
* |
* |
|
|
printf("Available commands:\n" |
printf("Available commands:\n" |
"bye Quit sftp\n" |
"bye Quit sftp\n" |
"cd path Change remote directory to 'path'\n" |
"cd path Change remote directory to 'path'\n" |
"chgrp grp path Change group of file 'path' to 'grp'\n" |
"chgrp [-h] grp path Change group of file 'path' to 'grp'\n" |
"chmod mode path Change permissions of file 'path' to 'mode'\n" |
"chmod [-h] mode path Change permissions of file 'path' to 'mode'\n" |
"chown own path Change owner of file 'path' to 'own'\n" |
"chown [-h] own path Change owner of file 'path' to 'own'\n" |
"df [-hi] [path] Display statistics for current directory or\n" |
"df [-hi] [path] Display statistics for current directory or\n" |
" filesystem containing 'path'\n" |
" filesystem containing 'path'\n" |
"exit Quit sftp\n" |
"exit Quit sftp\n" |
Line 367 make_absolute(char *p, const char *pwd) |
|
Line 367 make_absolute(char *p, const char *pwd) |
|
char *abs_str; |
char *abs_str; |
|
|
/* Derelativise */ |
/* Derelativise */ |
if (p && p[0] != '/') { |
if (p && !path_absolute(p)) { |
abs_str = path_append(pwd, p); |
abs_str = path_append(pwd, p); |
free(p); |
free(p); |
return(abs_str); |
return(abs_str); |
Line 540 parse_df_flags(const char *cmd, char **a |
|
Line 540 parse_df_flags(const char *cmd, char **a |
|
} |
} |
|
|
static int |
static int |
|
parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag) |
|
{ |
|
extern int opterr, optind, optopt, optreset; |
|
int ch; |
|
|
|
optind = optreset = 1; |
|
opterr = 0; |
|
|
|
*hflag = 0; |
|
while ((ch = getopt(argc, argv, "h")) != -1) { |
|
switch (ch) { |
|
case 'h': |
|
*hflag = 1; |
|
break; |
|
default: |
|
error("%s: Invalid flag -%c", cmd, optopt); |
|
return -1; |
|
} |
|
} |
|
|
|
return optind; |
|
} |
|
|
|
static int |
parse_no_flags(const char *cmd, char **argv, int argc) |
parse_no_flags(const char *cmd, char **argv, int argc) |
{ |
{ |
extern int opterr, optind, optopt, optreset; |
extern int opterr, optind, optopt, optreset; |
Line 1268 makeargv(const char *arg, int *argcp, in |
|
Line 1292 makeargv(const char *arg, int *argcp, in |
|
} |
} |
|
|
static int |
static int |
parse_args(const char **cpp, int *ignore_errors, int *aflag, |
parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag, |
int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, |
int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, |
int *rflag, int *sflag, |
int *rflag, int *sflag, |
unsigned long *n_arg, char **path1, char **path2) |
unsigned long *n_arg, char **path1, char **path2) |
Line 1282 parse_args(const char **cpp, int *ignore |
|
Line 1306 parse_args(const char **cpp, int *ignore |
|
/* Skip leading whitespace */ |
/* Skip leading whitespace */ |
cp = cp + strspn(cp, WHITESPACE); |
cp = cp + strspn(cp, WHITESPACE); |
|
|
/* Check for leading '-' (disable error processing) */ |
/* |
|
* Check for leading '-' (disable error processing) and '@' (suppress |
|
* command echo) |
|
*/ |
*ignore_errors = 0; |
*ignore_errors = 0; |
if (*cp == '-') { |
*disable_echo = 0; |
*ignore_errors = 1; |
for (;*cp != '\0'; cp++) { |
cp++; |
if (*cp == '-') { |
cp = cp + strspn(cp, WHITESPACE); |
*ignore_errors = 1; |
|
} else if (*cp == '@') { |
|
*disable_echo = 1; |
|
} else { |
|
/* all other characters terminate prefix processing */ |
|
break; |
|
} |
} |
} |
|
cp = cp + strspn(cp, WHITESPACE); |
|
|
/* Ignore blank lines and lines which begin with comment '#' char */ |
/* Ignore blank lines and lines which begin with comment '#' char */ |
if (*cp == '\0' || *cp == '#') |
if (*cp == '\0' || *cp == '#') |
Line 1415 parse_args(const char **cpp, int *ignore |
|
Line 1449 parse_args(const char **cpp, int *ignore |
|
case I_LUMASK: |
case I_LUMASK: |
case I_CHMOD: |
case I_CHMOD: |
base = 8; |
base = 8; |
|
/* FALLTHROUGH */ |
case I_CHOWN: |
case I_CHOWN: |
case I_CHGRP: |
case I_CHGRP: |
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) |
if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1) |
return -1; |
return -1; |
/* Get numeric arg (mandatory) */ |
/* Get numeric arg (mandatory) */ |
if (argc - optidx < 1) |
if (argc - optidx < 1) |
Line 1462 parse_args(const char **cpp, int *ignore |
|
Line 1497 parse_args(const char **cpp, int *ignore |
|
|
|
static int |
static int |
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, |
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, |
const char *startdir, int err_abort) |
const char *startdir, int err_abort, int echo_command) |
{ |
{ |
|
const char *ocmd = cmd; |
char *path1, *path2, *tmp; |
char *path1, *path2, *tmp; |
int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, |
int ignore_errors = 0, disable_echo = 1; |
iflag = 0; |
int aflag = 0, fflag = 0, hflag = 0, iflag = 0; |
int lflag = 0, pflag = 0, rflag = 0, sflag = 0; |
int lflag = 0, pflag = 0, rflag = 0, sflag = 0; |
int cmdnum, i; |
int cmdnum, i; |
unsigned long n_arg = 0; |
unsigned long n_arg = 0; |
Line 1476 parse_dispatch_command(struct sftp_conn |
|
Line 1512 parse_dispatch_command(struct sftp_conn |
|
glob_t g; |
glob_t g; |
|
|
path1 = path2 = NULL; |
path1 = path2 = NULL; |
cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, |
cmdnum = parse_args(&cmd, &ignore_errors, &disable_echo, &aflag, &fflag, |
&iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); |
&hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, |
|
&path1, &path2); |
if (ignore_errors != 0) |
if (ignore_errors != 0) |
err_abort = 0; |
err_abort = 0; |
|
|
|
if (echo_command && !disable_echo) |
|
mprintf("sftp> %s\n", ocmd); |
|
|
memset(&g, 0, sizeof(g)); |
memset(&g, 0, sizeof(g)); |
|
|
/* Perform command */ |
/* Perform command */ |
Line 1513 parse_dispatch_command(struct sftp_conn |
|
Line 1553 parse_dispatch_command(struct sftp_conn |
|
break; |
break; |
case I_SYMLINK: |
case I_SYMLINK: |
sflag = 1; |
sflag = 1; |
|
/* FALLTHROUGH */ |
case I_LINK: |
case I_LINK: |
if (!sflag) |
if (!sflag) |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
Line 1578 parse_dispatch_command(struct sftp_conn |
|
Line 1619 parse_dispatch_command(struct sftp_conn |
|
|
|
/* Strip pwd off beginning of non-absolute paths */ |
/* Strip pwd off beginning of non-absolute paths */ |
tmp = NULL; |
tmp = NULL; |
if (*path1 != '/') |
if (!path_absolute(path1)) |
tmp = *pwd; |
tmp = *pwd; |
|
|
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
Line 1630 parse_dispatch_command(struct sftp_conn |
|
Line 1671 parse_dispatch_command(struct sftp_conn |
|
if (!quiet) |
if (!quiet) |
mprintf("Changing mode on %s\n", |
mprintf("Changing mode on %s\n", |
g.gl_pathv[i]); |
g.gl_pathv[i]); |
err = do_setstat(conn, g.gl_pathv[i], &a); |
err = (hflag ? do_lsetstat : do_setstat)(conn, |
|
g.gl_pathv[i], &a); |
if (err != 0 && err_abort) |
if (err != 0 && err_abort) |
break; |
break; |
} |
} |
Line 1640 parse_dispatch_command(struct sftp_conn |
|
Line 1682 parse_dispatch_command(struct sftp_conn |
|
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { |
if (!(aa = (hflag ? do_lstat : do_stat)(conn, |
|
g.gl_pathv[i], 0))) { |
if (err_abort) { |
if (err_abort) { |
err = -1; |
err = -1; |
break; |
break; |
Line 1668 parse_dispatch_command(struct sftp_conn |
|
Line 1711 parse_dispatch_command(struct sftp_conn |
|
g.gl_pathv[i]); |
g.gl_pathv[i]); |
aa->gid = n_arg; |
aa->gid = n_arg; |
} |
} |
err = do_setstat(conn, g.gl_pathv[i], aa); |
err = (hflag ? do_lsetstat : do_setstat)(conn, |
|
g.gl_pathv[i], aa); |
if (err != 0 && err_abort) |
if (err != 0 && err_abort) |
break; |
break; |
} |
} |
Line 1905 complete_match(EditLine *el, struct sftp |
|
Line 1949 complete_match(EditLine *el, struct sftp |
|
xasprintf(&tmp, "%s*", file); |
xasprintf(&tmp, "%s*", file); |
|
|
/* Check if the path is absolute. */ |
/* Check if the path is absolute. */ |
isabs = tmp[0] == '/'; |
isabs = path_absolute(tmp); |
|
|
memset(&g, 0, sizeof(g)); |
memset(&g, 0, sizeof(g)); |
if (remote != LOCAL) { |
if (remote != LOCAL) { |
Line 2135 interactive_loop(struct sftp_conn *conn, |
|
Line 2179 interactive_loop(struct sftp_conn *conn, |
|
mprintf("Changing to: %s\n", dir); |
mprintf("Changing to: %s\n", dir); |
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
if (parse_dispatch_command(conn, cmd, |
if (parse_dispatch_command(conn, cmd, |
&remote_path, startdir, 1) != 0) { |
&remote_path, startdir, 1, 0) != 0) { |
free(dir); |
free(dir); |
free(startdir); |
free(startdir); |
free(remote_path); |
free(remote_path); |
Line 2149 interactive_loop(struct sftp_conn *conn, |
|
Line 2193 interactive_loop(struct sftp_conn *conn, |
|
file2 == NULL ? "" : " ", |
file2 == NULL ? "" : " ", |
file2 == NULL ? "" : file2); |
file2 == NULL ? "" : file2); |
err = parse_dispatch_command(conn, cmd, |
err = parse_dispatch_command(conn, cmd, |
&remote_path, startdir, 1); |
&remote_path, startdir, 1, 0); |
free(dir); |
free(dir); |
free(startdir); |
free(startdir); |
free(remote_path); |
free(remote_path); |
Line 2165 interactive_loop(struct sftp_conn *conn, |
|
Line 2209 interactive_loop(struct sftp_conn *conn, |
|
interactive = !batchmode && isatty(STDIN_FILENO); |
interactive = !batchmode && isatty(STDIN_FILENO); |
err = 0; |
err = 0; |
for (;;) { |
for (;;) { |
char *cp; |
|
const char *line; |
const char *line; |
int count = 0; |
int count = 0; |
|
|
Line 2179 interactive_loop(struct sftp_conn *conn, |
|
Line 2222 interactive_loop(struct sftp_conn *conn, |
|
printf("\n"); |
printf("\n"); |
break; |
break; |
} |
} |
if (!interactive) { /* Echo command */ |
|
mprintf("sftp> %s", cmd); |
|
if (strlen(cmd) > 0 && |
|
cmd[strlen(cmd) - 1] != '\n') |
|
printf("\n"); |
|
} |
|
} else { |
} else { |
if ((line = el_gets(el, &count)) == NULL || |
if ((line = el_gets(el, &count)) == NULL || |
count <= 0) { |
count <= 0) { |
Line 2198 interactive_loop(struct sftp_conn *conn, |
|
Line 2235 interactive_loop(struct sftp_conn *conn, |
|
} |
} |
} |
} |
|
|
cp = strrchr(cmd, '\n'); |
cmd[strcspn(cmd, "\n")] = '\0'; |
if (cp) |
|
*cp = '\0'; |
|
|
|
/* Handle user interrupts gracefully during commands */ |
/* Handle user interrupts gracefully during commands */ |
interrupted = 0; |
interrupted = 0; |
signal(SIGINT, cmd_interrupt); |
signal(SIGINT, cmd_interrupt); |
|
|
err = parse_dispatch_command(conn, cmd, &remote_path, |
err = parse_dispatch_command(conn, cmd, &remote_path, |
startdir, batchmode); |
startdir, batchmode, !interactive && el == NULL); |
if (err != 0) |
if (err != 0) |
break; |
break; |
} |
} |
|
|
|
|
fprintf(stderr, |
fprintf(stderr, |
"usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" |
"usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" |
" [-D sftp_server_path] [-F ssh_config] " |
" [-D sftp_server_path] [-F ssh_config] [-i identity_file]\n" |
"[-i identity_file] [-l limit]\n" |
" [-J destination] [-l limit] [-o ssh_option] [-P port]\n" |
" [-o ssh_option] [-P port] [-R num_requests] " |
" [-R num_requests] [-S program] [-s subsystem | sftp_server]\n" |
"[-S program]\n" |
" destination\n", |
" [-s subsystem | sftp_server] destination\n", |
|
__progname); |
__progname); |
exit(1); |
exit(1); |
} |
} |
Line 2324 main(int argc, char **argv) |
|
Line 2358 main(int argc, char **argv) |
|
infile = stdin; |
infile = stdin; |
|
|
while ((ch = getopt(argc, argv, |
while ((ch = getopt(argc, argv, |
"1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { |
"1246afhpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { |
switch (ch) { |
switch (ch) { |
/* Passed through to ssh(1) */ |
/* Passed through to ssh(1) */ |
case '4': |
case '4': |
Line 2334 main(int argc, char **argv) |
|
Line 2368 main(int argc, char **argv) |
|
break; |
break; |
/* Passed through to ssh(1) with argument */ |
/* Passed through to ssh(1) with argument */ |
case 'F': |
case 'F': |
|
case 'J': |
case 'c': |
case 'c': |
case 'i': |
case 'i': |
case 'o': |
case 'o': |