summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2021-08-07 00:12:10 +0000
committerDamien Miller <djm@cvs.openbsd.org>2021-08-07 00:12:10 +0000
commitacdcf31cdd76553d7ee8dd25282815738b279ab6 (patch)
tree028205b62601bf19f6026f700f8dd01460941155 /usr.bin/ssh
parent45cf9b23f72d035217835d5d5a7a252bbcde83da (diff)
make scp(1) in SFTP mode follow symlinks like traditional scp(1)
ok markus@
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/scp.c8
-rw-r--r--usr.bin/ssh/sftp-client.c58
-rw-r--r--usr.bin/ssh/sftp-client.h9
-rw-r--r--usr.bin/ssh/sftp.c8
4 files changed, 53 insertions, 30 deletions
diff --git a/usr.bin/ssh/scp.c b/usr.bin/ssh/scp.c
index 7aa6cdbb41e..04c7576accf 100644
--- a/usr.bin/ssh/scp.c
+++ b/usr.bin/ssh/scp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.220 2021/08/07 00:08:52 djm Exp $ */
+/* $OpenBSD: scp.c,v 1.221 2021/08/07 00:12:09 djm Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@@ -1257,7 +1257,7 @@ source_sftp(int argc, char *src, char *targ,
if (local_is_dir(src) && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
- SFTP_PROGRESS_ONLY, 0, 0) != 0) {
+ SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
fatal("failed to upload directory %s to %s",
src, abs_dst);
}
@@ -1489,7 +1489,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag, SFTP_PROGRESS_ONLY, 0, 0) == -1)
+ pflag, SFTP_PROGRESS_ONLY, 0, 0, 1) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
@@ -1894,7 +1894,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst,
- NULL, pflag, 1) == -1)
+ NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
err = -1;
} else {
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL,
diff --git a/usr.bin/ssh/sftp-client.c b/usr.bin/ssh/sftp-client.c
index 06e1d6db247..8a075aee308 100644
--- a/usr.bin/ssh/sftp-client.c
+++ b/usr.bin/ssh/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.149 2021/08/07 00:10:49 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.150 2021/08/07 00:12:09 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -1597,7 +1597,7 @@ do_download(struct sftp_conn *conn, const char *remote_path,
static int
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
- int resume_flag, int fsync_flag)
+ int resume_flag, int fsync_flag, int follow_link_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
@@ -1653,12 +1653,20 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
continue;
if (download_dir_internal(conn, new_src, new_dst,
depth + 1, &(dir_entries[i]->a), preserve_flag,
- print_flag, resume_flag, fsync_flag) == -1)
+ print_flag, resume_flag,
+ fsync_flag, follow_link_flag) == -1)
ret = -1;
- } else if (S_ISREG(dir_entries[i]->a.perm) ) {
+ } else if (S_ISREG(dir_entries[i]->a.perm) ||
+ (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
+ /*
+ * If this is a symlink then don't send the link's
+ * Attrib. do_download() will do a FXP_STAT operation
+ * and get the link target's attributes.
+ */
if (do_download(conn, new_src, new_dst,
- &(dir_entries[i]->a), preserve_flag,
- resume_flag, fsync_flag) == -1) {
+ S_ISLNK(dir_entries[i]->a.perm) ? NULL :
+ &(dir_entries[i]->a),
+ preserve_flag, resume_flag, fsync_flag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
@@ -1696,7 +1704,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int
download_dir(struct sftp_conn *conn, const char *src, const char *dst,
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
- int fsync_flag)
+ int fsync_flag, int follow_link_flag)
{
char *src_canon;
int ret;
@@ -1707,7 +1715,8 @@ download_dir(struct sftp_conn *conn, const char *src, const char *dst,
}
ret = download_dir_internal(conn, src_canon, dst, 0,
- dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
+ dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag,
+ follow_link_flag);
free(src_canon);
return ret;
}
@@ -1917,7 +1926,8 @@ do_upload(struct sftp_conn *conn, const char *local_path,
static int
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
- int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
+ int depth, int preserve_flag, int print_flag, int resume, int fsync_flag,
+ int follow_link_flag)
{
int ret = 0;
DIR *dirp;
@@ -1995,9 +2005,10 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
if (upload_dir_internal(conn, new_src, new_dst,
depth + 1, preserve_flag, print_flag, resume,
- fsync_flag) == -1)
+ fsync_flag, follow_link_flag) == -1)
ret = -1;
- } else if (S_ISREG(sb.st_mode)) {
+ } else if (S_ISREG(sb.st_mode) ||
+ (follow_link_flag && S_ISLNK(sb.st_mode))) {
if (do_upload(conn, new_src, new_dst,
preserve_flag, resume, fsync_flag) == -1) {
error("Uploading of file %s to %s failed!",
@@ -2018,7 +2029,8 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int
upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
- int preserve_flag, int print_flag, int resume, int fsync_flag)
+ int preserve_flag, int print_flag, int resume, int fsync_flag,
+ int follow_link_flag)
{
char *dst_canon;
int ret;
@@ -2029,7 +2041,7 @@ upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
- print_flag, resume, fsync_flag);
+ print_flag, resume, fsync_flag, follow_link_flag);
free(dst_canon);
return ret;
@@ -2353,7 +2365,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
static int
crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
- int depth, Attrib *dirattrib, int preserve_flag, int print_flag)
+ int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
+ int follow_link_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
@@ -2375,7 +2388,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
error("\"%s\" is not a directory", from_path);
return -1;
}
- if (print_flag)
+ if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
mprintf("Retrieving %s\n", from_path);
curdir = *dirattrib; /* dirattrib will be clobbered */
@@ -2427,10 +2440,17 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
if (crossload_dir_internal(from, to,
new_from_path, new_to_path,
depth + 1, &(dir_entries[i]->a), preserve_flag,
- print_flag) == -1)
+ print_flag, follow_link_flag) == -1)
ret = -1;
- } else if (S_ISREG(dir_entries[i]->a.perm) ) {
+ } else if (S_ISREG(dir_entries[i]->a.perm) ||
+ (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
+ /*
+ * If this is a symlink then don't send the link's
+ * Attrib. do_download() will do a FXP_STAT operation
+ * and get the link target's attributes.
+ */
if (do_crossload(from, to, new_from_path, new_to_path,
+ S_ISLNK(dir_entries[i]->a.perm) ? NULL :
&(dir_entries[i]->a), preserve_flag) == -1) {
error("Transfer of file %s to %s failed",
new_from_path, new_to_path);
@@ -2453,7 +2473,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
int
crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
- Attrib *dirattrib, int preserve_flag, int print_flag)
+ Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
{
char *from_path_canon;
int ret;
@@ -2464,7 +2484,7 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
}
ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0,
- dirattrib, preserve_flag, print_flag);
+ dirattrib, preserve_flag, print_flag, follow_link_flag);
free(from_path_canon);
return ret;
}
diff --git a/usr.bin/ssh/sftp-client.h b/usr.bin/ssh/sftp-client.h
index 03fe96b10c8..349094b4568 100644
--- a/usr.bin/ssh/sftp-client.h
+++ b/usr.bin/ssh/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.32 2021/08/07 00:08:52 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.33 2021/08/07 00:12:09 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -134,7 +134,7 @@ int do_download(struct sftp_conn *, const char *, const char *,
* times if 'pflag' is set
*/
int download_dir(struct sftp_conn *, const char *, const char *,
- Attrib *, int, int, int, int);
+ Attrib *, int, int, int, int, int);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
@@ -147,7 +147,7 @@ int do_upload(struct sftp_conn *, const char *, const char *, int, int, int);
* times if 'pflag' is set
*/
int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int,
- int);
+ int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to
@@ -164,7 +164,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
*/
int crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
- Attrib *dirattrib, int preserve_flag, int print_flag);
+ Attrib *dirattrib, int preserve_flag, int print_flag,
+ int follow_link_flag);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(const char *, const char *);
diff --git a/usr.bin/ssh/sftp.c b/usr.bin/ssh/sftp.c
index 69ba7ae7bb1..7a82302858f 100644
--- a/usr.bin/ssh/sftp.c
+++ b/usr.bin/ssh/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.209 2021/04/03 06:58:30 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.210 2021/08/07 00:12:09 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -633,10 +633,11 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
else if (!quiet && !resume)
mprintf("Fetching %s to %s\n",
g.gl_pathv[i], abs_dst);
+ /* XXX follow link flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, 1, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
@@ -726,10 +727,11 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
else if (!quiet && !resume)
mprintf("Uploading %s to %s\n",
g.gl_pathv[i], abs_dst);
+ /* XXX follow_link_flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,