summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2021-08-09 07:13:54 +0000
committerDamien Miller <djm@mindrot.org>2021-08-10 12:47:39 +1000
commit2b67932bb3176dee4fd447af4368789e04a82b93 (patch)
tree551bb1856aa534abff665cee1d60dfca8b3159a1 /scp.c
parent724eb900ace30661d45db2ba01d0f924d95ecccb (diff)
downloadopenssh-git-2b67932bb3176dee4fd447af4368789e04a82b93.tar.gz
upstream: on fatal errors, make scp wait for ssh connection before
exiting avoids LogLevel=verbose (or greater) messages from ssh appearing after scp has returned exited and control has returned to the shell; ok markus@ OpenBSD-Commit-ID: ef9dab5ef5ae54a6a4c3b15d380568e94263456c
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c89
1 files changed, 64 insertions, 25 deletions
diff --git a/scp.c b/scp.c
index fc97e1e7..c975e1c6 100644
--- a/scp.c
+++ b/scp.c
@@ -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).
@@ -165,7 +165,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;
@@ -448,8 +448,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 */
@@ -482,7 +481,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':
@@ -504,6 +503,9 @@ main(int argc, char **argv)
case '3':
throughlocal = 1;
break;
+ case 'R':
+ throughlocal = 0;
+ break;
case 'o':
case 'c':
case 'i':
@@ -514,6 +516,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)
@@ -523,14 +528,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);
@@ -1253,6 +1250,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)
@@ -1273,8 +1293,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 "
@@ -1471,6 +1491,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
@@ -1484,10 +1505,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) {
@@ -1895,11 +1917,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);
@@ -2000,9 +2021,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);
}
@@ -2141,3 +2162,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);
+}