diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2019-01-16 23:23:46 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2019-01-16 23:23:46 +0000 |
commit | 6a652d610ce0410f91d53a9a5d7ec69efeffed88 (patch) | |
tree | bb1051de5514c3231beb10874212f0390de126ca /usr.bin | |
parent | 7edbdc0870bf3b2a8844cd3508e8cd2612014c79 (diff) |
Add "-h" flag to sftp chown/chgrp/chmod commands to request they do
not follow symlinks. Requires recently-committed lsetstat@openssh.com
extension on the server side.
ok markus@ dtucker@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/ssh/sftp-client.c | 42 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-client.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/sftp.1 | 31 | ||||
-rw-r--r-- | usr.bin/ssh/sftp.c | 43 |
4 files changed, 103 insertions, 18 deletions
diff --git a/usr.bin/ssh/sftp-client.c b/usr.bin/ssh/sftp-client.c index a7f6353baf2..d6dd33bf6b8 100644 --- a/usr.bin/ssh/sftp-client.c +++ b/usr.bin/ssh/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> * @@ -72,6 +72,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; @@ -449,6 +450,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", @@ -1082,7 +1087,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 || @@ -1111,7 +1115,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 || @@ -1124,6 +1127,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) @@ -1133,7 +1168,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/usr.bin/ssh/sftp-client.h b/usr.bin/ssh/sftp-client.h index f814b07d6c8..b2324804508 100644 --- a/usr.bin/ssh/sftp-client.h +++ b/usr.bin/ssh/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> @@ -85,6 +85,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/usr.bin/ssh/sftp.1 b/usr.bin/ssh/sftp.1 index 7140bc19bcb..722a3441994 100644 --- a/usr.bin/ssh/sftp.1 +++ b/usr.bin/ssh/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/usr.bin/ssh/sftp.c b/usr.bin/ssh/sftp.c index 1a97fefee69..f552dcd599e 100644 --- a/usr.bin/ssh/sftp.c +++ b/usr.bin/ssh/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> * @@ -256,9 +256,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" @@ -540,6 +540,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; @@ -1428,7 +1452,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) @@ -1647,7 +1671,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; } @@ -1657,7 +1682,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; @@ -1685,7 +1711,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; } |