summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c79
1 files changed, 72 insertions, 7 deletions
diff --git a/sftp-server.c b/sftp-server.c
index ab1b063f2..19a132bd9 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.112 2018/06/01 03:33: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 {
@@ -117,7 +118,7 @@ struct sftp_handler {
117 int does_write; /* if nonzero, banned for readonly mode */ 118 int does_write; /* if nonzero, banned for readonly mode */
118}; 119};
119 120
120struct sftp_handler handlers[] = { 121static const struct sftp_handler handlers[] = {
121 /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */ 122 /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
122 { "open", NULL, SSH2_FXP_OPEN, process_open, 0 }, 123 { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
123 { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 }, 124 { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
@@ -141,18 +142,19 @@ struct sftp_handler handlers[] = {
141}; 142};
142 143
143/* SSH2_FXP_EXTENDED submessages */ 144/* SSH2_FXP_EXTENDED submessages */
144struct sftp_handler extended_handlers[] = { 145static const struct sftp_handler extended_handlers[] = {
145 { "posix-rename", "posix-rename@openssh.com", 0, 146 { "posix-rename", "posix-rename@openssh.com", 0,
146 process_extended_posix_rename, 1 }, 147 process_extended_posix_rename, 1 },
147 { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 }, 148 { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
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
154static int 156static int
155request_permitted(struct sftp_handler *h) 157request_permitted(const struct sftp_handler *h)
156{ 158{
157 char *result; 159 char *result;
158 160
@@ -285,9 +287,9 @@ enum {
285 HANDLE_FILE 287 HANDLE_FILE
286}; 288};
287 289
288Handle *handles = NULL; 290static Handle *handles = NULL;
289u_int num_handles = 0; 291static u_int num_handles = 0;
290int first_unused_handle = -1; 292static int first_unused_handle = -1;
291 293
292static void handle_unused(int i) 294static void handle_unused(int i)
293{ 295{
@@ -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;