summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sftp-client.c42
-rw-r--r--sftp-client.h5
-rw-r--r--sftp.131
-rw-r--r--sftp.c43
4 files changed, 103 insertions, 18 deletions
diff --git a/sftp-client.c b/sftp-client.c
index 4986d6d8..d3f80e5a 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.130 2018/07/31 03:07:24 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.131 2019/01/16 23:23:45 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -86,6 +86,7 @@ struct sftp_conn {
#define SFTP_EXT_FSTATVFS 0x00000004
#define SFTP_EXT_HARDLINK 0x00000008
#define SFTP_EXT_FSYNC 0x00000010
+#define SFTP_EXT_LSETSTAT 0x00000020
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
@@ -463,6 +464,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_FSYNC;
known = 1;
+ } else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
+ strcmp((char *)value, "1") == 0) {
+ ret->exts |= SFTP_EXT_LSETSTAT;
+ known = 1;
}
if (known) {
debug2("Server supports extension \"%s\" revision %s",
@@ -1096,7 +1101,6 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
- sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
@@ -1125,7 +1129,6 @@ do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
- sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
@@ -1138,6 +1141,38 @@ do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
}
#endif
+int
+do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
+{
+ struct sshbuf *msg;
+ u_int status, id;
+ int r;
+
+ if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
+ error("Server does not support lsetstat@openssh.com extension");
+ return -1;
+ }
+
+ id = conn->msg_id++;
+ if ((msg = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
+ (r = sshbuf_put_cstring(msg, path)) != 0 ||
+ (r = encode_attrib(msg, a)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
+ send_msg(conn, msg);
+ sshbuf_free(msg);
+
+ status = get_status(conn, id);
+ if (status != SSH2_FX_OK)
+ error("Couldn't setstat on \"%s\": %s", path,
+ fx2txt(status));
+
+ return status == SSH2_FX_OK ? 0 : -1;
+}
+
static void
send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
u_int len, const u_char *handle, u_int handle_len)
@@ -1147,7 +1182,6 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
- sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
diff --git a/sftp-client.h b/sftp-client.h
index 14a3b818..63a9b8b1 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.27 2015/05/08 06:45:13 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.28 2019/01/16 23:23:45 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -91,6 +91,9 @@ int do_setstat(struct sftp_conn *, const char *, Attrib *);
/* Set file attributes of open file 'handle' */
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
+/* Set file attributes of 'path', not following symlinks */
+int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
+
/* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, const char *);
diff --git a/sftp.1 b/sftp.1
index 7140bc19..722a3441 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.122 2018/11/16 02:30:20 djm Exp $
+.\" $OpenBSD: sftp.1,v 1.123 2019/01/16 23:23:45 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: November 16 2018 $
+.Dd $Mdocdate: January 16 2019 $
.Dt SFTP 1
.Os
.Sh NAME
@@ -316,31 +316,52 @@ Change remote directory to
If
.Ar path
is not specified, then change directory to the one the session started in.
-.It Ic chgrp Ar grp Ar path
+.It Xo Ic chgrp
+.Op Fl h
+.Ar grp
+.Ar path
+.Xc
Change group of file
.Ar path
to
.Ar grp .
+If the
+.Fl h
+flag is specified, then symlinks will not be followed.
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.Ar grp
must be a numeric GID.
-.It Ic chmod Ar mode Ar path
+.It Xo Ic chmod
+.Op Fl h
+.Ar mode
+.Ar path
+.Xc
Change permissions of file
.Ar path
to
.Ar mode .
+If the
+.Fl h
+flag is specified, then symlinks will not be followed.
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
-.It Ic chown Ar own Ar path
+.It Xo Ic chown
+.Op Fl h
+.Ar own
+.Ar path
+.Xc
Change owner of file
.Ar path
to
.Ar own .
+If the
+.Fl h
+flag is specified, then symlinks will not be followed.
.Ar path
may contain
.Xr glob 7
diff --git a/sftp.c b/sftp.c
index f886b330..0f3f89d3 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.188 2018/11/16 03:26:01 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.189 2019/01/16 23:23:45 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -278,9 +278,9 @@ help(void)
printf("Available commands:\n"
"bye Quit sftp\n"
"cd path Change remote directory to 'path'\n"
- "chgrp grp path Change group of file 'path' to 'grp'\n"
- "chmod mode path Change permissions of file 'path' to 'mode'\n"
- "chown own path Change owner of file 'path' to 'own'\n"
+ "chgrp [-h] grp path Change group of file 'path' to 'grp'\n"
+ "chmod [-h] mode path Change permissions of file 'path' to 'mode'\n"
+ "chown [-h] own path Change owner of file 'path' to 'own'\n"
"df [-hi] [path] Display statistics for current directory or\n"
" filesystem containing 'path'\n"
"exit Quit sftp\n"
@@ -562,6 +562,30 @@ parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
}
static int
+parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag)
+{
+ extern int opterr, optind, optopt, optreset;
+ int ch;
+
+ optind = optreset = 1;
+ opterr = 0;
+
+ *hflag = 0;
+ while ((ch = getopt(argc, argv, "h")) != -1) {
+ switch (ch) {
+ case 'h':
+ *hflag = 1;
+ break;
+ default:
+ error("%s: Invalid flag -%c", cmd, optopt);
+ return -1;
+ }
+ }
+
+ return optind;
+}
+
+static int
parse_no_flags(const char *cmd, char **argv, int argc)
{
extern int opterr, optind, optopt, optreset;
@@ -1456,7 +1480,7 @@ parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag,
/* FALLTHROUGH */
case I_CHOWN:
case I_CHGRP:
- if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
+ if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1)
return -1;
/* Get numeric arg (mandatory) */
if (argc - optidx < 1)
@@ -1675,7 +1699,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
if (!quiet)
mprintf("Changing mode on %s\n",
g.gl_pathv[i]);
- err = do_setstat(conn, g.gl_pathv[i], &a);
+ err = (hflag ? do_lsetstat : do_setstat)(conn,
+ g.gl_pathv[i], &a);
if (err != 0 && err_abort)
break;
}
@@ -1685,7 +1710,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
path1 = make_absolute(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
- if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
+ if (!(aa = (hflag ? do_lstat : do_stat)(conn,
+ g.gl_pathv[i], 0))) {
if (err_abort) {
err = -1;
break;
@@ -1713,7 +1739,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
g.gl_pathv[i]);
aa->gid = n_arg;
}
- err = do_setstat(conn, g.gl_pathv[i], aa);
+ err = (hflag ? do_lsetstat : do_setstat)(conn,
+ g.gl_pathv[i], aa);
if (err != 0 && err_abort)
break;
}