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
This commit is contained in:
djm@openbsd.org 2019-01-16 23:22:10 +00:00 committed by Damien Miller
parent 4a526941d3
commit dbbc7e0eab

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-server.c,v 1.113 2019/01/01 23:10: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 {
@ -148,6 +149,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 }
};
@ -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)
{
@ -1369,6 +1385,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)
{