on fatal errors, make scp wait for ssh connection before exiting
authordjm <djm@openbsd.org>
Mon, 9 Aug 2021 07:13:54 +0000 (07:13 +0000)
committerdjm <djm@openbsd.org>
Mon, 9 Aug 2021 07:13:54 +0000 (07:13 +0000)
avoids LogLevel=verbose (or greater) messages from ssh appearing
after scp has returned exited and control has returned to the
shell; ok markus@

usr.bin/ssh/scp.c
usr.bin/ssh/scp/Makefile

index 6a39bdb..53c5225 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.222 2021/08/07 01:57:08 dtucker Exp $ */
+/* $OpenBSD: scp.c,v 1.223 2021/08/09 07:13:54 djm Exp $ */
 /*
  * scp - secure remote copy.  This is basically patched BSD rcp which
  * uses ssh to do the data transfer (instead of using rcmd).
@@ -139,7 +139,7 @@ int showprogress = 1;
  * This is set to non-zero if remote-remote copy should be piped
  * through this process.
  */
-int throughlocal = 0;
+int throughlocal = 1;
 
 /* Non-standard port to use for the ssh connection or -1. */
 int sshport = -1;
@@ -422,8 +422,7 @@ main(int argc, char **argv)
        const char *errstr;
        extern char *optarg;
        extern int optind;
-       /* For now, keep SCP as default */
-       enum scp_mode_e mode = MODE_SCP;
+       enum scp_mode_e mode = MODE_SFTP;
        char *sftp_direct = NULL;
 
        /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -452,7 +451,7 @@ main(int argc, char **argv)
 
        fflag = Tflag = tflag = 0;
        while ((ch = getopt(argc, argv,
-           "12346ABCTdfpqrtvD:F:J:M:P:S:c:i:l:o:")) != -1) {
+           "12346ABCORTdfpqrtvD:F:J:P:S:c:i:l:o:")) != -1) {
                switch (ch) {
                /* User-visible flags. */
                case '1':
@@ -474,6 +473,9 @@ main(int argc, char **argv)
                case '3':
                        throughlocal = 1;
                        break;
+               case 'R':
+                       throughlocal = 0;
+                       break;
                case 'o':
                case 'c':
                case 'i':
@@ -484,6 +486,9 @@ main(int argc, char **argv)
                        addargs(&args, "-%c", ch);
                        addargs(&args, "%s", optarg);
                        break;
+               case 'O':
+                       mode = MODE_SCP;
+                       break;
                case 'P':
                        sshport = a2port(optarg);
                        if (sshport <= 0)
@@ -493,14 +498,6 @@ main(int argc, char **argv)
                        addargs(&remote_remote_args, "-oBatchmode=yes");
                        addargs(&args, "-oBatchmode=yes");
                        break;
-               case 'M':
-                       if (strcmp(optarg, "sftp") == 0)
-                               mode = MODE_SFTP;
-                       else if (strcmp(optarg, "scp") == 0)
-                               mode = MODE_SCP;
-                       else
-                               usage();
-                       break;
                case 'l':
                        limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
                            &errstr);
@@ -1220,6 +1217,29 @@ tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
        free(src);
 }
 
+/* Canonicalise a remote path, handling ~ by assuming cwd is the homedir */
+static char *
+absolute_remote_path(const char *path, const char *remote_path)
+{
+       char *ret;
+
+       /* Handle ~ prefixed paths */
+       if (*path != '~')
+               ret = xstrdup(path);
+       else {
+               if (strcmp(path, "~") == 0)
+                       ret = xstrdup("");
+               else if (strncmp(path, "~/", 2) == 0)
+                       ret = xstrdup(path + 2);
+               else {
+                       /* XXX could be supported with protocol extension */
+                       error("~user paths are not currently supported");
+                       return NULL;
+               }
+       }
+       return make_absolute(ret, remote_path);
+}
+
 void
 source_sftp(int argc, char *src, char *targ,
     struct sftp_conn *conn, char **remote_path)
@@ -1240,8 +1260,8 @@ source_sftp(int argc, char *src, char *targ,
         * No need to glob here - the local shell already took care of
         * the expansions
         */
-       target = xstrdup(targ);
-       target = make_absolute(target, *remote_path);
+       if ((target = absolute_remote_path(targ, *remote_path)) == NULL)
+               cleanup_exit(255);
        target_is_dir = remote_is_dir(conn, target);
        if (targetshouldbedirectory && !target_is_dir) {
                fatal("Target is not a directory, but more files selected "
@@ -1438,6 +1458,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
        char *filename, *tmp = NULL, *remote_path = NULL;
        int i, r, err = 0;
 
+       memset(&g, 0, sizeof(g));
        /*
         * Here, we need remote glob as SFTP can not depend on remote shell
         * expansions
@@ -1451,10 +1472,11 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
                goto out;
        }
 
-       abs_src = xstrdup(src);
-       abs_src = make_absolute(abs_src, remote_path);
+       if ((abs_src = absolute_remote_path(src, remote_path)) == NULL) {
+               err = -1;
+               goto out;
+       }
        free(remote_path);
-       memset(&g, 0, sizeof(g));
 
        debug3_f("copying remote %s to local %s", abs_src, dst);
        if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
@@ -1854,11 +1876,10 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
        if ((filename = basename(src)) == NULL)
                fatal("basename %s: %s", src, strerror(errno));
 
-       abs_src = xstrdup(src);
-       abs_src = make_absolute(abs_src, from_remote_path);
+       if ((abs_src = absolute_remote_path(src, from_remote_path)) == NULL ||
+           (target = absolute_remote_path(targ, *to_remote_path)) == NULL)
+               cleanup_exit(255);
        free(from_remote_path);
-       target = xstrdup(targ);
-       target = make_absolute(target, *to_remote_path);
        memset(&g, 0, sizeof(g));
 
        targetisdir = remote_is_dir(to, target);
@@ -1959,9 +1980,9 @@ void
 usage(void)
 {
        (void) fprintf(stderr,
-           "usage: scp [-346ABCpqrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
-           "           [-i identity_file] [-J destination] [-l limit] [-M scp|sftp]\n"
-           "           [-o ssh_option] [-P port] [-S program] source ... target\n");
+           "usage: scp [-346ABCOpqrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
+           "           [-i identity_file] [-J destination] [-l limit] [-o ssh_option]\n"
+           "           [-P port] [-S program] source ... target\n");
        exit(1);
 }
 
@@ -2096,3 +2117,21 @@ lostconn(int signo)
        else
                exit(1);
 }
+
+void
+cleanup_exit(int i)
+{
+       if (remin > 0)
+               close(remin);
+       if (remout > 0)
+               close(remout);
+       if (remin2 > 0)
+               close(remin2);
+       if (remout2 > 0)
+               close(remout2);
+       if (do_cmd_pid > 0)
+               waitpid(do_cmd_pid, NULL, 0);
+       if (do_cmd_pid2 > 0)
+               waitpid(do_cmd_pid2, NULL, 0);
+       exit(i);
+}
index 705f59a..8e2d11b 100644 (file)
@@ -1,9 +1,9 @@
-#      $OpenBSD: Makefile,v 1.22 2021/08/02 23:38:27 djm Exp $
+#      $OpenBSD: Makefile,v 1.23 2021/08/09 07:13:54 djm Exp $
 
 .PATH:         ${.CURDIR}/..
 
 SRCS=  scp.c
-SRCS+= atomicio.c cleanup.c fatal.c progressmeter.c utf8.c
+SRCS+= fatal.c atomicio.c progressmeter.c utf8.c
 SRCS+= sftp-common.c sftp-client.c sftp-glob.c
 SRCS+= ${SRCS_BASE}