mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-12-22 10:00:14 +00:00
upstream: 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@ OpenBSD-Commit-ID: f93bb3f6f7eb2fb7ef1e59126e72714f1626d604
This commit is contained in:
parent
dbbc7e0eab
commit
60d8c84e08
@ -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 ||
|
||||
|
@ -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 *);
|
||||
|
||||
|
31
sftp.1
31
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
|
||||
|
43
sftp.c
43
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"
|
||||
@ -561,6 +561,30 @@ parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
|
||||
return optind;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user