diff options
Diffstat (limited to 'sftp-server.c')
-rw-r--r-- | sftp-server.c | 67 |
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); | |||
107 | static void process_extended_fstatvfs(u_int32_t id); | 107 | static void process_extended_fstatvfs(u_int32_t id); |
108 | static void process_extended_hardlink(u_int32_t id); | 108 | static void process_extended_hardlink(u_int32_t id); |
109 | static void process_extended_fsync(u_int32_t id); | 109 | static void process_extended_fsync(u_int32_t id); |
110 | static void process_extended_lsetstat(u_int32_t id); | ||
110 | static void process_extended(u_int32_t id); | 111 | static void process_extended(u_int32_t id); |
111 | 112 | ||
112 | struct sftp_handler { | 113 | struct 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 | ||
896 | static struct timespec * | ||
897 | attrib_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 | |||
892 | static void | 908 | static void |
893 | process_setstat(u_int32_t id) | 909 | process_setstat(u_int32_t id) |
894 | { | 910 | { |
@@ -1370,6 +1386,55 @@ process_extended_fsync(u_int32_t id) | |||
1370 | } | 1386 | } |
1371 | 1387 | ||
1372 | static void | 1388 | static void |
1389 | process_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 | |||
1437 | static void | ||
1373 | process_extended(u_int32_t id) | 1438 | process_extended(u_int32_t id) |
1374 | { | 1439 | { |
1375 | char *request; | 1440 | char *request; |