summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-01-16 23:22:10 +0000
committerDamien Miller <djm@mindrot.org>2019-01-17 11:08:13 +1100
commitdbbc7e0eab7262f34b8e0cd6efecd1c77b905ed0 (patch)
treeafd7da975b2b45d1a7d0c97c235a54c1c738d07a /sftp-server.c
parent4a526941d328fc3d97068c6a4cbd9b71b70fe5e1 (diff)
upstream: add support for a "lsetstat@openssh.com" extension. This
replicates the functionality of the existing SSH2_FXP_SETSTAT operation but does not follow symlinks. Based on a patch from Bert Haverkamp in bz#2067 but with more attribute modifications supported. ok markus@ dtucker@ OpenBSD-Commit-ID: f7234f6e90db19655d55d936a115ee4ccb6aaf80
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/sftp-server.c b/sftp-server.c
index de9ad3d3b..19a132bd9 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.113 2019/01/01 23:10:53 djm Exp $ */ 1/* $OpenBSD: sftp-server.c,v 1.114 2019/01/16 23:22:10 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
4 * 4 *
@@ -107,6 +107,7 @@ static void process_extended_statvfs(u_int32_t id);
107static void process_extended_fstatvfs(u_int32_t id); 107static void process_extended_fstatvfs(u_int32_t id);
108static void process_extended_hardlink(u_int32_t id); 108static void process_extended_hardlink(u_int32_t id);
109static void process_extended_fsync(u_int32_t id); 109static void process_extended_fsync(u_int32_t id);
110static void process_extended_lsetstat(u_int32_t id);
110static void process_extended(u_int32_t id); 111static void process_extended(u_int32_t id);
111 112
112struct sftp_handler { 113struct sftp_handler {
@@ -148,6 +149,7 @@ static const struct sftp_handler extended_handlers[] = {
148 { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 }, 149 { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
149 { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 }, 150 { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
150 { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, 151 { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
152 { "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
151 { NULL, NULL, 0, NULL, 0 } 153 { NULL, NULL, 0, NULL, 0 }
152}; 154};
153 155
@@ -666,6 +668,8 @@ process_init(void)
666 (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ 668 (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
667 /* fsync extension */ 669 /* fsync extension */
668 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || 670 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
671 (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
672 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
669 (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */ 673 (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
670 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 674 fatal("%s: buffer error: %s", __func__, ssh_err(r));
671 send_msg(msg); 675 send_msg(msg);
@@ -889,6 +893,18 @@ attrib_to_tv(const Attrib *a)
889 return tv; 893 return tv;
890} 894}
891 895
896static struct timespec *
897attrib_to_ts(const Attrib *a)
898{
899 static struct timespec ts[2];
900
901 ts[0].tv_sec = a->atime;
902 ts[0].tv_nsec = 0;
903 ts[1].tv_sec = a->mtime;
904 ts[1].tv_nsec = 0;
905 return ts;
906}
907
892static void 908static void
893process_setstat(u_int32_t id) 909process_setstat(u_int32_t id)
894{ 910{
@@ -1370,6 +1386,55 @@ process_extended_fsync(u_int32_t id)
1370} 1386}
1371 1387
1372static void 1388static void
1389process_extended_lsetstat(u_int32_t id)
1390{
1391 Attrib a;
1392 char *name;
1393 int r, status = SSH2_FX_OK;
1394
1395 if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
1396 (r = decode_attrib(iqueue, &a)) != 0)
1397 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1398
1399 debug("request %u: lsetstat name \"%s\"", id, name);
1400 if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
1401 /* nonsensical for links */
1402 status = SSH2_FX_BAD_MESSAGE;
1403 goto out;
1404 }
1405 if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1406 logit("set \"%s\" mode %04o", name, a.perm);
1407 r = fchmodat(AT_FDCWD, name,
1408 a.perm & 07777, AT_SYMLINK_NOFOLLOW);
1409 if (r == -1)
1410 status = errno_to_portable(errno);
1411 }
1412 if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1413 char buf[64];
1414 time_t t = a.mtime;
1415
1416 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
1417 localtime(&t));
1418 logit("set \"%s\" modtime %s", name, buf);
1419 r = utimensat(AT_FDCWD, name,
1420 attrib_to_ts(&a), AT_SYMLINK_NOFOLLOW);
1421 if (r == -1)
1422 status = errno_to_portable(errno);
1423 }
1424 if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
1425 logit("set \"%s\" owner %lu group %lu", name,
1426 (u_long)a.uid, (u_long)a.gid);
1427 r = fchownat(AT_FDCWD, name, a.uid, a.gid,
1428 AT_SYMLINK_NOFOLLOW);
1429 if (r == -1)
1430 status = errno_to_portable(errno);
1431 }
1432 out:
1433 send_status(id, status);
1434 free(name);
1435}
1436
1437static void
1373process_extended(u_int32_t id) 1438process_extended(u_int32_t id)
1374{ 1439{
1375 char *request; 1440 char *request;