[openssh-commits] [openssh] 09/10: upstream: make scp(1) in SFTP mode follow symlinks like

git+noreply at mindrot.org git+noreply at mindrot.org
Sat Aug 7 10:27:23 AEST 2021


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 7b1cbcb7599d9f6a3bbad79d412604aa1203b5ee
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Sat Aug 7 00:12:09 2021 +0000

    upstream: make scp(1) in SFTP mode follow symlinks like
    
    traditional scp(1) ok markus@
    
    OpenBSD-Commit-ID: 97255e55be37e8e26605e4ba1e69f9781765d231
---
 scp.c         |  8 ++++----
 sftp-client.c | 58 +++++++++++++++++++++++++++++++++++++++-------------------
 sftp-client.h |  9 +++++----
 sftp.c        |  8 +++++---
 4 files changed, 53 insertions(+), 30 deletions(-)

diff --git a/scp.c b/scp.c
index 51925455..3eb0212b 100644
--- a/scp.c
+++ b/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).
@@ -1290,7 +1290,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);
 		}
@@ -1522,7 +1522,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,
@@ -1935,7 +1935,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/sftp-client.c b/sftp-client.c
index d4ddc94f..40fae328 100644
--- a/sftp-client.c
+++ b/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 at openbsd.org>
  *
@@ -1615,7 +1615,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;
@@ -1671,12 +1671,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;
@@ -1714,7 +1722,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;
@@ -1725,7 +1733,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;
 }
@@ -1936,7 +1945,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;
@@ -2014,9 +2024,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!",
@@ -2037,7 +2048,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;
@@ -2048,7 +2060,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;
@@ -2372,7 +2384,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;
@@ -2394,7 +2407,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 */
@@ -2446,10 +2459,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);
@@ -2472,7 +2492,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;
@@ -2483,7 +2503,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/sftp-client.h b/sftp-client.h
index 1de6ba8f..00707f7c 100644
--- a/sftp-client.h
+++ b/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 at openbsd.org>
@@ -140,7 +140,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
@@ -153,7 +153,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
@@ -170,7 +170,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/sftp.c b/sftp.c
index 3f46c553..95b2e0b7 100644
--- a/sftp.c
+++ b/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 at openbsd.org>
  *
@@ -655,10 +655,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,
@@ -748,10 +749,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,

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list