summaryrefslogtreecommitdiff
path: root/sftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp.c')
-rw-r--r--sftp.c118
1 files changed, 76 insertions, 42 deletions
diff --git a/sftp.c b/sftp.c
index 7db86c2d3..44aa19d96 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp.c,v 1.186 2018/09/07 04:26:56 dtucker Exp $ */ 1/* $OpenBSD: sftp.c,v 1.190 2019/01/21 22:50:42 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -278,9 +278,9 @@ help(void)
278 printf("Available commands:\n" 278 printf("Available commands:\n"
279 "bye Quit sftp\n" 279 "bye Quit sftp\n"
280 "cd path Change remote directory to 'path'\n" 280 "cd path Change remote directory to 'path'\n"
281 "chgrp grp path Change group of file 'path' to 'grp'\n" 281 "chgrp [-h] grp path Change group of file 'path' to 'grp'\n"
282 "chmod mode path Change permissions of file 'path' to 'mode'\n" 282 "chmod [-h] mode path Change permissions of file 'path' to 'mode'\n"
283 "chown own path Change owner of file 'path' to 'own'\n" 283 "chown [-h] own path Change owner of file 'path' to 'own'\n"
284 "df [-hi] [path] Display statistics for current directory or\n" 284 "df [-hi] [path] Display statistics for current directory or\n"
285 " filesystem containing 'path'\n" 285 " filesystem containing 'path'\n"
286 "exit Quit sftp\n" 286 "exit Quit sftp\n"
@@ -389,7 +389,7 @@ make_absolute(char *p, const char *pwd)
389 char *abs_str; 389 char *abs_str;
390 390
391 /* Derelativise */ 391 /* Derelativise */
392 if (p && p[0] != '/') { 392 if (p && !path_absolute(p)) {
393 abs_str = path_append(pwd, p); 393 abs_str = path_append(pwd, p);
394 free(p); 394 free(p);
395 return(abs_str); 395 return(abs_str);
@@ -562,6 +562,30 @@ parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
562} 562}
563 563
564static int 564static int
565parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag)
566{
567 extern int opterr, optind, optopt, optreset;
568 int ch;
569
570 optind = optreset = 1;
571 opterr = 0;
572
573 *hflag = 0;
574 while ((ch = getopt(argc, argv, "h")) != -1) {
575 switch (ch) {
576 case 'h':
577 *hflag = 1;
578 break;
579 default:
580 error("%s: Invalid flag -%c", cmd, optopt);
581 return -1;
582 }
583 }
584
585 return optind;
586}
587
588static int
565parse_no_flags(const char *cmd, char **argv, int argc) 589parse_no_flags(const char *cmd, char **argv, int argc)
566{ 590{
567 extern int opterr, optind, optopt, optreset; 591 extern int opterr, optind, optopt, optreset;
@@ -1296,7 +1320,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1296} 1320}
1297 1321
1298static int 1322static int
1299parse_args(const char **cpp, int *ignore_errors, int *aflag, 1323parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag,
1300 int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, 1324 int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1301 int *rflag, int *sflag, 1325 int *rflag, int *sflag,
1302 unsigned long *n_arg, char **path1, char **path2) 1326 unsigned long *n_arg, char **path1, char **path2)
@@ -1310,13 +1334,23 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
1310 /* Skip leading whitespace */ 1334 /* Skip leading whitespace */
1311 cp = cp + strspn(cp, WHITESPACE); 1335 cp = cp + strspn(cp, WHITESPACE);
1312 1336
1313 /* Check for leading '-' (disable error processing) */ 1337 /*
1338 * Check for leading '-' (disable error processing) and '@' (suppress
1339 * command echo)
1340 */
1314 *ignore_errors = 0; 1341 *ignore_errors = 0;
1315 if (*cp == '-') { 1342 *disable_echo = 0;
1316 *ignore_errors = 1; 1343 for (;*cp != '\0'; cp++) {
1317 cp++; 1344 if (*cp == '-') {
1318 cp = cp + strspn(cp, WHITESPACE); 1345 *ignore_errors = 1;
1346 } else if (*cp == '@') {
1347 *disable_echo = 1;
1348 } else {
1349 /* all other characters terminate prefix processing */
1350 break;
1351 }
1319 } 1352 }
1353 cp = cp + strspn(cp, WHITESPACE);
1320 1354
1321 /* Ignore blank lines and lines which begin with comment '#' char */ 1355 /* Ignore blank lines and lines which begin with comment '#' char */
1322 if (*cp == '\0' || *cp == '#') 1356 if (*cp == '\0' || *cp == '#')
@@ -1446,7 +1480,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
1446 /* FALLTHROUGH */ 1480 /* FALLTHROUGH */
1447 case I_CHOWN: 1481 case I_CHOWN:
1448 case I_CHGRP: 1482 case I_CHGRP:
1449 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1483 if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1)
1450 return -1; 1484 return -1;
1451 /* Get numeric arg (mandatory) */ 1485 /* Get numeric arg (mandatory) */
1452 if (argc - optidx < 1) 1486 if (argc - optidx < 1)
@@ -1491,11 +1525,12 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
1491 1525
1492static int 1526static int
1493parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, 1527parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1494 const char *startdir, int err_abort) 1528 const char *startdir, int err_abort, int echo_command)
1495{ 1529{
1530 const char *ocmd = cmd;
1496 char *path1, *path2, *tmp; 1531 char *path1, *path2, *tmp;
1497 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, 1532 int ignore_errors = 0, disable_echo = 1;
1498 iflag = 0; 1533 int aflag = 0, fflag = 0, hflag = 0, iflag = 0;
1499 int lflag = 0, pflag = 0, rflag = 0, sflag = 0; 1534 int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1500 int cmdnum, i; 1535 int cmdnum, i;
1501 unsigned long n_arg = 0; 1536 unsigned long n_arg = 0;
@@ -1505,11 +1540,15 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1505 glob_t g; 1540 glob_t g;
1506 1541
1507 path1 = path2 = NULL; 1542 path1 = path2 = NULL;
1508 cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, 1543 cmdnum = parse_args(&cmd, &ignore_errors, &disable_echo, &aflag, &fflag,
1509 &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); 1544 &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg,
1545 &path1, &path2);
1510 if (ignore_errors != 0) 1546 if (ignore_errors != 0)
1511 err_abort = 0; 1547 err_abort = 0;
1512 1548
1549 if (echo_command && !disable_echo)
1550 mprintf("sftp> %s\n", ocmd);
1551
1513 memset(&g, 0, sizeof(g)); 1552 memset(&g, 0, sizeof(g));
1514 1553
1515 /* Perform command */ 1554 /* Perform command */
@@ -1608,7 +1647,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1608 1647
1609 /* Strip pwd off beginning of non-absolute paths */ 1648 /* Strip pwd off beginning of non-absolute paths */
1610 tmp = NULL; 1649 tmp = NULL;
1611 if (*path1 != '/') 1650 if (!path_absolute(path1))
1612 tmp = *pwd; 1651 tmp = *pwd;
1613 1652
1614 path1 = make_absolute(path1, *pwd); 1653 path1 = make_absolute(path1, *pwd);
@@ -1660,7 +1699,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1660 if (!quiet) 1699 if (!quiet)
1661 mprintf("Changing mode on %s\n", 1700 mprintf("Changing mode on %s\n",
1662 g.gl_pathv[i]); 1701 g.gl_pathv[i]);
1663 err = do_setstat(conn, g.gl_pathv[i], &a); 1702 err = (hflag ? do_lsetstat : do_setstat)(conn,
1703 g.gl_pathv[i], &a);
1664 if (err != 0 && err_abort) 1704 if (err != 0 && err_abort)
1665 break; 1705 break;
1666 } 1706 }
@@ -1670,7 +1710,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1670 path1 = make_absolute(path1, *pwd); 1710 path1 = make_absolute(path1, *pwd);
1671 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1711 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1672 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1712 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1673 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { 1713 if (!(aa = (hflag ? do_lstat : do_stat)(conn,
1714 g.gl_pathv[i], 0))) {
1674 if (err_abort) { 1715 if (err_abort) {
1675 err = -1; 1716 err = -1;
1676 break; 1717 break;
@@ -1698,7 +1739,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1698 g.gl_pathv[i]); 1739 g.gl_pathv[i]);
1699 aa->gid = n_arg; 1740 aa->gid = n_arg;
1700 } 1741 }
1701 err = do_setstat(conn, g.gl_pathv[i], aa); 1742 err = (hflag ? do_lsetstat : do_setstat)(conn,
1743 g.gl_pathv[i], aa);
1702 if (err != 0 && err_abort) 1744 if (err != 0 && err_abort)
1703 break; 1745 break;
1704 } 1746 }
@@ -1936,7 +1978,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1936 xasprintf(&tmp, "%s*", file); 1978 xasprintf(&tmp, "%s*", file);
1937 1979
1938 /* Check if the path is absolute. */ 1980 /* Check if the path is absolute. */
1939 isabs = tmp[0] == '/'; 1981 isabs = path_absolute(tmp);
1940 1982
1941 memset(&g, 0, sizeof(g)); 1983 memset(&g, 0, sizeof(g));
1942 if (remote != LOCAL) { 1984 if (remote != LOCAL) {
@@ -2169,7 +2211,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2169 mprintf("Changing to: %s\n", dir); 2211 mprintf("Changing to: %s\n", dir);
2170 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 2212 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
2171 if (parse_dispatch_command(conn, cmd, 2213 if (parse_dispatch_command(conn, cmd,
2172 &remote_path, startdir, 1) != 0) { 2214 &remote_path, startdir, 1, 0) != 0) {
2173 free(dir); 2215 free(dir);
2174 free(startdir); 2216 free(startdir);
2175 free(remote_path); 2217 free(remote_path);
@@ -2183,7 +2225,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2183 file2 == NULL ? "" : " ", 2225 file2 == NULL ? "" : " ",
2184 file2 == NULL ? "" : file2); 2226 file2 == NULL ? "" : file2);
2185 err = parse_dispatch_command(conn, cmd, 2227 err = parse_dispatch_command(conn, cmd,
2186 &remote_path, startdir, 1); 2228 &remote_path, startdir, 1, 0);
2187 free(dir); 2229 free(dir);
2188 free(startdir); 2230 free(startdir);
2189 free(remote_path); 2231 free(remote_path);
@@ -2199,8 +2241,6 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2199 interactive = !batchmode && isatty(STDIN_FILENO); 2241 interactive = !batchmode && isatty(STDIN_FILENO);
2200 err = 0; 2242 err = 0;
2201 for (;;) { 2243 for (;;) {
2202 char *cp;
2203
2204 signal(SIGINT, SIG_IGN); 2244 signal(SIGINT, SIG_IGN);
2205 2245
2206 if (el == NULL) { 2246 if (el == NULL) {
@@ -2211,12 +2251,6 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2211 printf("\n"); 2251 printf("\n");
2212 break; 2252 break;
2213 } 2253 }
2214 if (!interactive) { /* Echo command */
2215 mprintf("sftp> %s", cmd);
2216 if (strlen(cmd) > 0 &&
2217 cmd[strlen(cmd) - 1] != '\n')
2218 printf("\n");
2219 }
2220 } else { 2254 } else {
2221#ifdef USE_LIBEDIT 2255#ifdef USE_LIBEDIT
2222 const char *line; 2256 const char *line;
@@ -2235,16 +2269,14 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2235#endif /* USE_LIBEDIT */ 2269#endif /* USE_LIBEDIT */
2236 } 2270 }
2237 2271
2238 cp = strrchr(cmd, '\n'); 2272 cmd[strcspn(cmd, "\n")] = '\0';
2239 if (cp)
2240 *cp = '\0';
2241 2273
2242 /* Handle user interrupts gracefully during commands */ 2274 /* Handle user interrupts gracefully during commands */
2243 interrupted = 0; 2275 interrupted = 0;
2244 signal(SIGINT, cmd_interrupt); 2276 signal(SIGINT, cmd_interrupt);
2245 2277
2246 err = parse_dispatch_command(conn, cmd, &remote_path, 2278 err = parse_dispatch_command(conn, cmd, &remote_path,
2247 startdir, batchmode); 2279 startdir, batchmode, !interactive && el == NULL);
2248 if (err != 0) 2280 if (err != 0)
2249 break; 2281 break;
2250 } 2282 }
@@ -2330,11 +2362,10 @@ usage(void)
2330 2362
2331 fprintf(stderr, 2363 fprintf(stderr,
2332 "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2364 "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2333 " [-D sftp_server_path] [-F ssh_config] " 2365 " [-D sftp_server_path] [-F ssh_config] [-i identity_file]\n"
2334 "[-i identity_file] [-l limit]\n" 2366 " [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
2335 " [-o ssh_option] [-P port] [-R num_requests] " 2367 " [-R num_requests] [-S program] [-s subsystem | sftp_server]\n"
2336 "[-S program]\n" 2368 " destination\n",
2337 " [-s subsystem | sftp_server] destination\n",
2338 __progname); 2369 __progname);
2339 exit(1); 2370 exit(1);
2340} 2371}
@@ -2362,6 +2393,8 @@ main(int argc, char **argv)
2362 sanitise_stdfd(); 2393 sanitise_stdfd();
2363 msetlocale(); 2394 msetlocale();
2364 2395
2396 seed_rng();
2397
2365 __progname = ssh_get_progname(argv[0]); 2398 __progname = ssh_get_progname(argv[0]);
2366 memset(&args, '\0', sizeof(args)); 2399 memset(&args, '\0', sizeof(args));
2367 args.list = NULL; 2400 args.list = NULL;
@@ -2375,7 +2408,7 @@ main(int argc, char **argv)
2375 infile = stdin; 2408 infile = stdin;
2376 2409
2377 while ((ch = getopt(argc, argv, 2410 while ((ch = getopt(argc, argv,
2378 "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { 2411 "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) {
2379 switch (ch) { 2412 switch (ch) {
2380 /* Passed through to ssh(1) */ 2413 /* Passed through to ssh(1) */
2381 case '4': 2414 case '4':
@@ -2385,6 +2418,7 @@ main(int argc, char **argv)
2385 break; 2418 break;
2386 /* Passed through to ssh(1) with argument */ 2419 /* Passed through to ssh(1) with argument */
2387 case 'F': 2420 case 'F':
2421 case 'J':
2388 case 'c': 2422 case 'c':
2389 case 'i': 2423 case 'i':
2390 case 'o': 2424 case 'o':