summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2022-01-17 21:39:52 +0000
committerDamien Miller <djm@cvs.openbsd.org>2022-01-17 21:39:52 +0000
commit3df929d3a2b034e9a365df93a012f8c2a363eb6d (patch)
tree12e78b139c735fea7eb87e0f9192a9cd1ca18b03 /usr.bin/ssh
parent49a83b846d92c900d95e39188926f4214f6bd67a (diff)
when transferring multiple files in SFTP mode, create the destination
directory if it doesn't already exist to match olde-scp(1) behaviour. noticed by deraadt@ ok markus@
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/scp.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/usr.bin/ssh/scp.c b/usr.bin/ssh/scp.c
index c0e05735885..7f94d74b94d 100644
--- a/usr.bin/ssh/scp.c
+++ b/usr.bin/ssh/scp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.242 2022/01/08 07:36:11 djm Exp $ */
+/* $OpenBSD: scp.c,v 1.243 2022/01/17 21:39:51 djm Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@@ -106,6 +106,7 @@
#include "misc.h"
#include "progressmeter.h"
#include "utf8.h"
+#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
@@ -1241,10 +1242,16 @@ void
source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
{
char *target = NULL, *filename = NULL, *abs_dst = NULL;
- int target_is_dir;
-
+ int src_is_dir, target_is_dir;
+ Attrib a;
+ struct stat st;
+
+ memset(&a, '\0', sizeof(a));
+ if (stat(src, &st) != 0)
+ fatal("stat local \"%s\": %s", src, strerror(errno));
+ src_is_dir = S_ISDIR(st.st_mode);
if ((filename = basename(src)) == NULL)
- fatal("basename %s: %s", src, strerror(errno));
+ fatal("basename \"%s\": %s", src, strerror(errno));
/*
* No need to glob here - the local shell already took care of
@@ -1254,8 +1261,12 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
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 "
- "for upload");
+ debug("target directory \"%s\" does not exist", target);
+ a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
+ a.perm = st.st_mode | 0700; /* ensure writable */
+ if (do_mkdir(conn, target, &a, 1) != 0)
+ cleanup_exit(255); /* error already logged */
+ target_is_dir = 1;
}
if (target_is_dir)
abs_dst = path_append(target, filename);
@@ -1265,7 +1276,7 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
}
debug3_f("copying local %s to remote %s", src, abs_dst);
- if (local_is_dir(src) && iamrecursive) {
+ if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
error("failed to upload directory %s to %s",
@@ -1449,14 +1460,15 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
char *abs_dst = NULL;
glob_t g;
char *filename, *tmp = NULL;
- int i, r, err = 0;
+ int i, r, err = 0, dst_is_dir;
+ struct stat st;
memset(&g, 0, sizeof(g));
+
/*
* Here, we need remote glob as SFTP can not depend on remote shell
* expansions
*/
-
if ((abs_src = prepare_remote_path(conn, src)) == NULL) {
err = -1;
goto out;
@@ -1472,11 +1484,24 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
goto out;
}
- if (g.gl_matchc > 1 && !local_is_dir(dst)) {
- error("Multiple files match pattern, but destination "
- "\"%s\" is not a directory", dst);
- err = -1;
- goto out;
+ if ((r = stat(dst, &st)) != 0)
+ debug2_f("stat local \"%s\": %s", dst, strerror(errno));
+ dst_is_dir = r == 0 && S_ISDIR(st.st_mode);
+
+ if (g.gl_matchc > 1 && !dst_is_dir) {
+ if (r == 0) {
+ error("Multiple files match pattern, but destination "
+ "\"%s\" is not a directory", dst);
+ err = -1;
+ goto out;
+ }
+ debug2_f("creating destination \"%s\"", dst);
+ if (mkdir(dst, 0777) != 0) {
+ error("local mkdir \"%s\": %s", dst, strerror(errno));
+ err = -1;
+ goto out;
+ }
+ dst_is_dir = 1;
}
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
@@ -1487,7 +1512,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
goto out;
}
- if (local_is_dir(dst))
+ if (dst_is_dir)
abs_dst = path_append(dst, filename);
else
abs_dst = xstrdup(dst);