summaryrefslogtreecommitdiff
path: root/sftp-client.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2021-08-09 23:47:44 +0000
committerDamien Miller <djm@mindrot.org>2021-08-10 12:47:46 +1000
commit2ab864010e0a93c5dd95116fb5ceaf430e2fc23c (patch)
tree2851434ba4912fd244aa2e327580b606e86b159e /sftp-client.c
parent41b019ac067f1d1f7d99914d0ffee4d2a547c3d8 (diff)
downloadopenssh-git-2ab864010e0a93c5dd95116fb5ceaf430e2fc23c.tar.gz
upstream: SFTP protocol extension to allow the server to expand
~-prefixed paths, in particular ~user ones. Allows scp in sftp mode to accept these paths, like scp in rcp mode does. prompted by and much discussion deraadt@ ok markus@ OpenBSD-Commit-ID: 7d794def9e4de348e1e777f6030fc9bafdfff392
Diffstat (limited to 'sftp-client.c')
-rw-r--r--sftp-client.c59
1 files changed, 49 insertions, 10 deletions
diff --git a/sftp-client.c b/sftp-client.c
index ce31c35a..5bfff90d 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.153 2021/08/09 07:16:09 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.154 2021/08/09 23:47:44 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -102,6 +102,7 @@ struct sftp_conn {
#define SFTP_EXT_FSYNC 0x00000010
#define SFTP_EXT_LSETSTAT 0x00000020
#define SFTP_EXT_LIMITS 0x00000040
+#define SFTP_EXT_PATH_EXPAND 0x00000080
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
@@ -529,6 +530,10 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_LIMITS;
known = 1;
+ } else if (strcmp(name, "expand-path@openssh.com") == 0 &&
+ strcmp((char *)value, "1") == 0) {
+ ret->exts |= SFTP_EXT_PATH_EXPAND;
+ known = 1;
}
if (known) {
debug2("Server supports extension \"%s\" revision %s",
@@ -964,8 +969,9 @@ do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
return status == SSH2_FX_OK ? 0 : -1;
}
-char *
-do_realpath(struct sftp_conn *conn, const char *path)
+/* Implements both the realpath and expand-path operations */
+static char *
+do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
{
struct sshbuf *msg;
u_int expected_id, count, id;
@@ -973,14 +979,26 @@ do_realpath(struct sftp_conn *conn, const char *path)
Attrib a;
u_char type;
int r;
+ const char *what = "SSH2_FXP_REALPATH";
- expected_id = id = conn->msg_id++;
- send_string_request(conn, id, SSH2_FXP_REALPATH, path,
- strlen(path));
-
+ if (expand)
+ what = "expand-path@openssh.com";
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
+ expected_id = id = conn->msg_id++;
+ if (expand) {
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_cstring(msg,
+ "expand-path@openssh.com")) != 0 ||
+ (r = sshbuf_put_cstring(msg, path)) != 0)
+ fatal_fr(r, "compose %s", what);
+ send_msg(conn, msg);
+ } else {
+ send_string_request(conn, id, SSH2_FXP_REALPATH,
+ path, strlen(path));
+ }
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
@@ -1004,15 +1022,14 @@ do_realpath(struct sftp_conn *conn, const char *path)
if ((r = sshbuf_get_u32(msg, &count)) != 0)
fatal_fr(r, "parse count");
if (count != 1)
- fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
+ fatal("Got multiple names (%d) from %s", count, what);
if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
(r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
(r = decode_attrib(msg, &a)) != 0)
fatal_fr(r, "parse filename/attrib");
- debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
- (unsigned long)a.size);
+ debug3("%s %s -> %s", what, path, filename);
free(longname);
@@ -1021,6 +1038,28 @@ do_realpath(struct sftp_conn *conn, const char *path)
return(filename);
}
+char *
+do_realpath(struct sftp_conn *conn, const char *path)
+{
+ return do_realpath_expand(conn, path, 0);
+}
+
+int
+can_expand_path(struct sftp_conn *conn)
+{
+ return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
+}
+
+char *
+do_expand_path(struct sftp_conn *conn, const char *path)
+{
+ if (!can_expand_path(conn)) {
+ debug3_f("no server support, fallback to realpath");
+ return do_realpath_expand(conn, path, 0);
+ }
+ return do_realpath_expand(conn, path, 1);
+}
+
int
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
int force_legacy)