diff options
author | Ed Maste <emaste@FreeBSD.org> | 2020-02-14 19:47:15 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2020-02-14 19:47:15 +0000 |
commit | f02e39982452024dafcf0ea6e536ebff586ffce4 (patch) | |
tree | 78cdaad953cc879dc7d97272436a4d84b228d94c /sftp-server.c | |
parent | dc9e8d9c8401178683a1f53bc816389a1160dc41 (diff) |
Notes
Diffstat (limited to 'sftp-server.c')
-rw-r--r-- | sftp-server.c | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/sftp-server.c b/sftp-server.c index ab1b063f21360..19a132bd91ce4 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.112 2018/06/01 03:33:53 djm Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.114 2019/01/16 23:22:10 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -107,6 +107,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 { @@ -117,7 +118,7 @@ struct sftp_handler { int does_write; /* if nonzero, banned for readonly mode */ }; -struct sftp_handler handlers[] = { +static const struct sftp_handler handlers[] = { /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */ { "open", NULL, SSH2_FXP_OPEN, process_open, 0 }, { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 }, @@ -141,18 +142,19 @@ struct sftp_handler handlers[] = { }; /* SSH2_FXP_EXTENDED submessages */ -struct sftp_handler extended_handlers[] = { +static const struct sftp_handler extended_handlers[] = { { "posix-rename", "posix-rename@openssh.com", 0, process_extended_posix_rename, 1 }, { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 }, { "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 } }; static int -request_permitted(struct sftp_handler *h) +request_permitted(const struct sftp_handler *h) { char *result; @@ -285,9 +287,9 @@ enum { HANDLE_FILE }; -Handle *handles = NULL; -u_int num_handles = 0; -int first_unused_handle = -1; +static Handle *handles = NULL; +static u_int num_handles = 0; +static int first_unused_handle = -1; static void handle_unused(int i) { @@ -666,6 +668,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); @@ -889,6 +893,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) { @@ -1370,6 +1386,55 @@ process_extended_fsync(u_int32_t id) } 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) { char *request; |