[openssh-commits] [openssh] 01/01: upstream: When doing an sftp recursive upload or download of a

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Nov 20 16:58:39 AEDT 2020


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

dtucker pushed a commit to branch master
in repository openssh.

commit 41935882f4e82de60dbd6e033eabe79e1b963518
Author: dtucker at openbsd.org <dtucker at openbsd.org>
Date:   Fri Nov 20 03:16:56 2020 +0000

    upstream: When doing an sftp recursive upload or download of a
    
    read-only directory, ensure that the directory is created with write and
    execute permissions in the interim so that we can actually complete the
    transfer, then set the directory permission as the final step.  (The execute
    bit is only likely to be an issue with a non-POSIX server).  bz#3222, ok djm@
    
    OpenBSD-Commit-ID: a82606212f2796e31f0e1af94a63355a7ad5d903
---
 sftp-client.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/sftp-client.c b/sftp-client.c
index 6c2a4fb7..d82e31ae 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.137 2020/10/18 11:32:02 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.138 2020/11/20 03:16:56 dtucker Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm at openbsd.org>
  *
@@ -1496,7 +1496,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 	int i, ret = 0;
 	SFTP_DIRENT **dir_entries;
 	char *filename, *new_src = NULL, *new_dst = NULL;
-	mode_t mode = 0777;
+	mode_t mode = 0777, tmpmode = mode;
 
 	if (depth >= MAX_DIR_DEPTH) {
 		error("Maximum directory depth exceeded: %d levels", depth);
@@ -1515,14 +1515,15 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 	if (print_flag)
 		mprintf("Retrieving %s\n", src);
 
-	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
 		mode = dirattrib->perm & 01777;
-	else {
+		tmpmode = mode | (S_IWUSR|S_IXUSR);
+	} else {
 		debug("Server did not send permissions for "
 		    "directory \"%s\"", dst);
 	}
 
-	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
+	if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) {
 		error("mkdir %s: %s", dst, strerror(errno));
 		return -1;
 	}
@@ -1577,6 +1578,10 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 			    "\"%s\"", dst);
 	}
 
+	if (mode != tmpmode && chmod(dst, mode) == -1)
+		error("Can't set final mode on \"%s\": %s", dst,
+		    strerror(errno));
+
 	free_sftp_dirents(dir_entries);
 
 	return ret;
@@ -1829,6 +1834,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 	char *filename, *new_src = NULL, *new_dst = NULL;
 	struct stat sb;
 	Attrib a, *dirattrib;
+	u_int32_t saved_perm;
 
 	if (depth >= MAX_DIR_DEPTH) {
 		error("Maximum directory depth exceeded: %d levels", depth);
@@ -1858,8 +1864,11 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 	/*
 	 * sftp lacks a portable status value to match errno EEXIST,
 	 * so if we get a failure back then we must check whether
-	 * the path already existed and is a directory.
+	 * the path already existed and is a directory.  Ensure we can
+	 * write to the directory we create for the duration of the transfer.
 	 */
+	saved_perm = a.perm;
+	a.perm |= (S_IWUSR|S_IXUSR);
 	if (do_mkdir(conn, dst, &a, 0) != 0) {
 		if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
 			return -1;
@@ -1868,6 +1877,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
 			return -1;
 		}
 	}
+	a.perm = saved_perm;
 
 	if ((dirp = opendir(src)) == NULL) {
 		error("Failed to open dir \"%s\": %s", src, strerror(errno));

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


More information about the openssh-commits mailing list