Bugzilla – Attachment 3219 Details for
Bug 2067
lsetstat extension to sftp-server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
sftp-server lsetstat extension, sftp client chmod/chgrp/chown -h flag
sftp-lsetstat.diff (text/plain), 10.62 KB, created by
Damien Miller
on 2019-01-04 15:46:54 AEDT
(
hide
)
Description:
sftp-server lsetstat extension, sftp client chmod/chgrp/chown -h flag
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2019-01-04 15:46:54 AEDT
Size:
10.62 KB
patch
obsolete
>diff --git a/sftp-client.c b/sftp-client.c >index a7f6353..683ebfc 100644 >--- a/sftp-client.c >+++ b/sftp-client.c >@@ -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/sftp-client.h b/sftp-client.h >index f814b07..734331a 100644 >--- a/sftp-client.h >+++ b/sftp-client.h >@@ -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/sftp-server.c b/sftp-server.c >index b48a580..d180b96 100644 >--- a/sftp-server.c >+++ b/sftp-server.c >@@ -99,6 +99,7 @@ static void process_extended_statvfs(u_int32_t id); > static void process_extended_fstatvfs(u_int32_t id); > static void process_extended_hardlink(u_int32_t id); > static void process_extended_fsync(u_int32_t id); >+static void process_extended_lsetstat(u_int32_t id); > static void process_extended(u_int32_t id); > > struct sftp_handler { >@@ -140,6 +141,7 @@ static const struct sftp_handler extended_handlers[] = { > { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 }, > { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 }, > { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, >+ { "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 }, > { NULL, NULL, 0, NULL, 0 } > }; > >@@ -658,6 +660,8 @@ process_init(void) > (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ > /* fsync extension */ > (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || >+ (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ >+ (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || > (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */ > fatal("%s: buffer error: %s", __func__, ssh_err(r)); > send_msg(msg); >@@ -881,6 +885,18 @@ attrib_to_tv(const Attrib *a) > return tv; > } > >+static struct timespec * >+attrib_to_ts(const Attrib *a) >+{ >+ static struct timespec ts[2]; >+ >+ ts[0].tv_sec = a->atime; >+ ts[0].tv_nsec = 0; >+ ts[1].tv_sec = a->mtime; >+ ts[1].tv_nsec = 0; >+ return ts; >+} >+ > static void > process_setstat(u_int32_t id) > { >@@ -1342,6 +1358,55 @@ process_extended_fsync(u_int32_t id) > send_status(id, status); > } > >+static void >+process_extended_lsetstat(u_int32_t id) >+{ >+ Attrib a; >+ char *name; >+ int r, status = SSH2_FX_OK; >+ >+ if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || >+ (r = decode_attrib(iqueue, &a)) != 0) >+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); >+ >+ debug("request %u: lsetstat name \"%s\"", id, name); >+ if (a.flags & SSH2_FILEXFER_ATTR_SIZE) { >+ /* nonsensical for links */ >+ status = SSH2_FX_BAD_MESSAGE; >+ goto out; >+ } >+ if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { >+ logit("set \"%s\" mode %04o", name, a.perm); >+ r = fchmodat(AT_FDCWD, name, >+ a.perm & 07777, AT_SYMLINK_NOFOLLOW); >+ if (r == -1) >+ status = errno_to_portable(errno); >+ } >+ if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { >+ char buf[64]; >+ time_t t = a.mtime; >+ >+ strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S", >+ localtime(&t)); >+ logit("set \"%s\" modtime %s", name, buf); >+ r = utimensat(AT_FDCWD, name, >+ attrib_to_ts(&a), AT_SYMLINK_NOFOLLOW); >+ if (r == -1) >+ status = errno_to_portable(errno); >+ } >+ if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { >+ logit("set \"%s\" owner %lu group %lu", name, >+ (u_long)a.uid, (u_long)a.gid); >+ r = fchownat(AT_FDCWD, name, a.uid, a.gid, >+ AT_SYMLINK_NOFOLLOW); >+ if (r == -1) >+ status = errno_to_portable(errno); >+ } >+ out: >+ send_status(id, status); >+ free(name); >+} >+ > static void > process_extended(u_int32_t id) > { >diff --git a/sftp.1 b/sftp.1 >index 7140bc1..af1d4b4 100644 >--- a/sftp.1 >+++ b/sftp.1 >@@ -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 1a97fef..cee46d6 100644 >--- a/sftp.c >+++ b/sftp.c >@@ -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" >@@ -539,6 +539,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) > { >@@ -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; > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
dtucker
:
ok+
Actions:
View
|
Diff
Attachments on
bug 2067
:
2212
|
2213
| 3219