[PATCH 1/4] scp/sftp: add -V for setting SFTP protocol version

Mike Frysinger vapier at gentoo.org
Fri Oct 1 06:49:19 AEST 2021


This makes it easier to force specific protocol versions, and will
make it easier to add experimental SFTPv4 support while keeping v3
as the default.

I'm not super in love with using -V for this (since that is often a
shorthand for --version), but it's one of the few remaining short
options that haven't been allocated and can be consistent across the
3 tools that utilize SFTP.
---
 scp.c         | 13 +++++++++++--
 sftp-client.c |  7 ++++++-
 sftp-common.c |  3 +++
 sftp-common.h |  2 ++
 sftp-server.c | 17 +++++++++++++++--
 sftp.c        | 11 ++++++++++-
 sftp.h        |  3 ---
 7 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/scp.c b/scp.c
index 73ce8554d788..9623c310a5ba 100644
--- a/scp.c
+++ b/scp.c
@@ -134,6 +134,9 @@
 #include "sftp-common.h"
 #include "sftp-client.h"
 
+/* The max SFTP version we support */
+#define SSH2_FILEXFER_VERSION_MAX	3
+
 extern char *__progname;
 
 #define COPY_BUFLEN	16384
@@ -444,7 +447,7 @@ int
 main(int argc, char **argv)
 {
 	int ch, fflag, tflag, status, n;
-	char **newargv, *argv0;
+	char **newargv, *argv0, *cp;
 	const char *errstr;
 	extern char *optarg;
 	extern int optind;
@@ -481,7 +484,7 @@ main(int argc, char **argv)
 
 	fflag = Tflag = tflag = 0;
 	while ((ch = getopt(argc, argv,
-	    "12346ABCTdfOpqRrstvD:F:J:M:P:S:c:i:l:o:")) != -1) {
+	    "12346ABCTdfOpqRrstvD:F:J:M:P:S:c:i:l:o:V:")) != -1) {
 		switch (ch) {
 		/* User-visible flags. */
 		case '1':
@@ -562,6 +565,12 @@ main(int argc, char **argv)
 			addargs(&remote_remote_args, "-q");
 			showprogress = 0;
 			break;
+		case 'V':
+			sftp_version = strtol(optarg, &cp, 10);
+			/* Assume min version is 0 to avoid compiler warning */
+			if (sftp_version > SSH2_FILEXFER_VERSION_MAX)
+				fatal("Unsupported SFTP version %i", sftp_version);
+			break;
 
 		/* Server options. */
 		case 'd':
diff --git a/sftp-client.c b/sftp-client.c
index dc55ee7a4594..99f2a5c28e95 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -471,7 +471,7 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
 	if ((msg = sshbuf_new()) == NULL)
 		fatal_f("sshbuf_new failed");
 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
-	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
+	    (r = sshbuf_put_u32(msg, sftp_version)) != 0)
 		fatal_fr(r, "parse");
 
 	send_msg(ret, msg);
@@ -492,6 +492,11 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
 		fatal_fr(r, "parse version");
 
 	debug2("Remote version: %u", ret->version);
+	if (ret->version != sftp_version) {
+		debug("Changing local SFTP version from %u to %u", sftp_version,
+		    ret->version);
+		sftp_version = ret->version;
+	}
 
 	/* Check for extensions */
 	while (sshbuf_len(msg) > 0) {
diff --git a/sftp-common.c b/sftp-common.c
index 3ad57673d41e..7681206728a7 100644
--- a/sftp-common.c
+++ b/sftp-common.c
@@ -50,6 +50,9 @@
 #include "sftp.h"
 #include "sftp-common.h"
 
+/* The version of SFTP to use by default */
+unsigned int sftp_version = 3;
+
 /* Clear contents of attributes structure */
 void
 attrib_clear(Attrib *a)
diff --git a/sftp-common.h b/sftp-common.h
index 2e778a9ca0ba..5fc8b45da39a 100644
--- a/sftp-common.h
+++ b/sftp-common.h
@@ -31,6 +31,8 @@
 struct sshbuf;
 typedef struct Attrib Attrib;
 
+extern unsigned int sftp_version;
+
 /* File attributes */
 struct Attrib {
 	u_int32_t	flags;
diff --git a/sftp-server.c b/sftp-server.c
index 11fdb46de16d..859e93f31111 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -53,6 +53,9 @@
 #include "sftp.h"
 #include "sftp-common.h"
 
+/* The max SFTP version we support */
+#define SSH2_FILEXFER_VERSION_MAX	3
+
 char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
 
 /* Maximum data read that we are willing to accept */
@@ -703,8 +706,12 @@ process_init(void)
 	verbose("received client version %u", version);
 	if ((msg = sshbuf_new()) == NULL)
 		fatal_f("sshbuf_new failed");
+	if (version < sftp_version) {
+		verbose("downgrading server version from %u", sftp_version);
+		sftp_version = version;
+	}
 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_VERSION)) != 0 ||
-	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
+	    (r = sshbuf_put_u32(msg, sftp_version)) != 0)
 		fatal_fr(r, "compose");
 
 	 /* extension advertisments */
@@ -1844,7 +1851,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
 	pw = pwcopy(user_pw);
 
 	while (!skipargs && (ch = getopt(argc, argv,
-	    "d:f:l:P:p:Q:u:cehR")) != -1) {
+	    "d:f:l:P:p:Q:u:cehRV:")) != -1) {
 		switch (ch) {
 		case 'Q':
 			if (strcasecmp(optarg, "requests") != 0) {
@@ -1906,6 +1913,12 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
 				fatal("Invalid umask \"%s\"", optarg);
 			(void)umask((mode_t)mask);
 			break;
+		case 'V':
+			sftp_version = strtol(optarg, &cp, 10);
+			/* Assume min version is 0 to avoid compiler warning */
+			if (sftp_version > SSH2_FILEXFER_VERSION_MAX)
+				fatal("Unsupported SFTP version %i", sftp_version);
+			break;
 		case 'h':
 		default:
 			sftp_server_usage();
diff --git a/sftp.c b/sftp.c
index 04a1cf72d45f..725ce2872b4a 100644
--- a/sftp.c
+++ b/sftp.c
@@ -70,6 +70,9 @@ typedef void EditLine;
 #include "sftp-common.h"
 #include "sftp-client.h"
 
+/* The max SFTP version we support */
+#define SSH2_FILEXFER_VERSION_MAX	3
+
 /* File to read commands from */
 FILE* infile;
 
@@ -2395,7 +2398,7 @@ main(int argc, char **argv)
 	infile = stdin;
 
 	while ((ch = getopt(argc, argv,
-	    "1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) {
+	    "1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:V:")) != -1) {
 		switch (ch) {
 		/* Passed through to ssh(1) */
 		case 'A':
@@ -2492,6 +2495,12 @@ main(int argc, char **argv)
 			ssh_program = optarg;
 			replacearg(&args, 0, "%s", ssh_program);
 			break;
+		case 'V':
+			sftp_version = strtol(optarg, &cp, 10);
+			/* Assume min version is 0 to avoid compiler warning */
+			if (sftp_version > SSH2_FILEXFER_VERSION_MAX)
+				fatal("Unsupported SFTP version %i", sftp_version);
+			break;
 		case 'h':
 		default:
 			usage();
diff --git a/sftp.h b/sftp.h
index 2bde8bb7ff0a..4c22bcc81bb6 100644
--- a/sftp.h
+++ b/sftp.h
@@ -28,9 +28,6 @@
  * draft-ietf-secsh-filexfer-01.txt
  */
 
-/* version */
-#define	SSH2_FILEXFER_VERSION		3
-
 /* client to server */
 #define SSH2_FXP_INIT			1
 #define SSH2_FXP_OPEN			3
-- 
2.33.0



More information about the openssh-unix-dev mailing list