From 8ff680368b0bccf88ae85d4c99de69387fbad7a6 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 19 Sep 2022 10:43:12 +0000 Subject: [PATCH] upstream: sftp client library support for users-groups-by-id@openssh.com; ok markus@ OpenBSD-Commit-ID: ddb2f33a2da6349a9a89a8b5bcb9ca7c999394de --- sftp-client.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++---- sftp-client.h | 11 +++- 2 files changed, 140 insertions(+), 11 deletions(-) diff --git a/sftp-client.c b/sftp-client.c index 310d44e5e..35be53d69 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.164 2022/05/15 23:47:21 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.165 2022/09/19 10:43:12 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -95,15 +95,16 @@ struct sftp_conn { u_int num_requests; u_int version; u_int msg_id; -#define SFTP_EXT_POSIX_RENAME 0x00000001 -#define SFTP_EXT_STATVFS 0x00000002 -#define SFTP_EXT_FSTATVFS 0x00000004 -#define SFTP_EXT_HARDLINK 0x00000008 -#define SFTP_EXT_FSYNC 0x00000010 -#define SFTP_EXT_LSETSTAT 0x00000020 -#define SFTP_EXT_LIMITS 0x00000040 -#define SFTP_EXT_PATH_EXPAND 0x00000080 -#define SFTP_EXT_COPY_DATA 0x00000100 +#define SFTP_EXT_POSIX_RENAME 0x00000001 +#define SFTP_EXT_STATVFS 0x00000002 +#define SFTP_EXT_FSTATVFS 0x00000004 +#define SFTP_EXT_HARDLINK 0x00000008 +#define SFTP_EXT_FSYNC 0x00000010 +#define SFTP_EXT_LSETSTAT 0x00000020 +#define SFTP_EXT_LIMITS 0x00000040 +#define SFTP_EXT_PATH_EXPAND 0x00000080 +#define SFTP_EXT_COPY_DATA 0x00000100 +#define SFTP_EXT_GETUSERSGROUPS_BY_ID 0x00000200 u_int exts; u_int64_t limit_kbps; struct bwlimit bwlimit_in, bwlimit_out; @@ -539,6 +540,11 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, strcmp((char *)value, "1") == 0) { ret->exts |= SFTP_EXT_COPY_DATA; known = 1; + } else if (strcmp(name, + "users-groups-by-id@openssh.com") == 0 && + strcmp((char *)value, "1") == 0) { + ret->exts |= SFTP_EXT_GETUSERSGROUPS_BY_ID; + known = 1; } if (known) { debug2("Server supports extension \"%s\" revision %s", @@ -2752,6 +2758,120 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to, return ret; } +int +can_get_users_groups_by_id(struct sftp_conn *conn) +{ + return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0; +} + +int +do_get_users_groups_by_id(struct sftp_conn *conn, + const u_int *uids, u_int nuids, + const u_int *gids, u_int ngids, + char ***usernamesp, char ***groupnamesp) +{ + struct sshbuf *msg, *uidbuf, *gidbuf; + u_int i, expected_id, id; + char *name, **usernames = NULL, **groupnames = NULL; + u_char type; + int r; + + *usernamesp = *groupnamesp = NULL; + if (!can_get_users_groups_by_id(conn)) + return SSH_ERR_FEATURE_UNSUPPORTED; + + if ((msg = sshbuf_new()) == NULL || + (uidbuf = sshbuf_new()) == NULL || + (gidbuf = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + expected_id = id = conn->msg_id++; + debug2("Sending SSH2_FXP_EXTENDED(users-groups-by-id@openssh.com)"); + for (i = 0; i < nuids; i++) { + if ((r = sshbuf_put_u32(uidbuf, uids[i])) != 0) + fatal_fr(r, "compose uids"); + } + for (i = 0; i < ngids; i++) { + if ((r = sshbuf_put_u32(gidbuf, gids[i])) != 0) + fatal_fr(r, "compose gids"); + } + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, + "users-groups-by-id@openssh.com")) != 0 || + (r = sshbuf_put_stringb(msg, uidbuf)) != 0 || + (r = sshbuf_put_stringb(msg, gidbuf)) != 0) + fatal_fr(r, "compose"); + send_msg(conn, msg); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal_fr(r, "parse"); + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + u_int status; + char *errmsg; + + if ((r = sshbuf_get_u32(msg, &status)) != 0 || + (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) + fatal_fr(r, "parse status"); + error("users-groups-by-id %s", + *errmsg == '\0' ? fx2txt(status) : errmsg); + free(errmsg); + sshbuf_free(msg); + sshbuf_free(uidbuf); + sshbuf_free(gidbuf); + return -1; + } else if (type != SSH2_FXP_EXTENDED_REPLY) + fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", + SSH2_FXP_EXTENDED_REPLY, type); + + /* reuse */ + sshbuf_free(uidbuf); + sshbuf_free(gidbuf); + uidbuf = gidbuf = NULL; + if ((r = sshbuf_froms(msg, &uidbuf)) != 0 || + (r = sshbuf_froms(msg, &gidbuf)) != 0) + fatal_fr(r, "parse response"); + if (nuids > 0) { + usernames = xcalloc(nuids, sizeof(*usernames)); + for (i = 0; i < nuids; i++) { + if ((r = sshbuf_get_cstring(uidbuf, &name, NULL)) != 0) + fatal_fr(r, "parse user name"); + /* Handle unresolved names */ + if (*name == '\0') { + free(name); + name = NULL; + } + usernames[i] = name; + } + } + if (ngids > 0) { + groupnames = xcalloc(ngids, sizeof(*groupnames)); + for (i = 0; i < ngids; i++) { + if ((r = sshbuf_get_cstring(gidbuf, &name, NULL)) != 0) + fatal_fr(r, "parse user name"); + /* Handle unresolved names */ + if (*name == '\0') { + free(name); + name = NULL; + } + groupnames[i] = name; + } + } + if (sshbuf_len(uidbuf) != 0) + fatal_f("unexpected extra username data"); + if (sshbuf_len(gidbuf) != 0) + fatal_f("unexpected extra groupname data"); + sshbuf_free(uidbuf); + sshbuf_free(gidbuf); + sshbuf_free(msg); + /* success */ + *usernamesp = usernames; + *groupnamesp = groupnames; + return 0; +} + char * path_append(const char *p1, const char *p2) { diff --git a/sftp-client.h b/sftp-client.h index 7ca6e8ad9..d7deab17e 100644 --- a/sftp-client.h +++ b/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.37 2022/05/13 06:31:50 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.38 2022/09/19 10:43:12 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -183,6 +183,15 @@ int crossload_dir(struct sftp_conn *from, struct sftp_conn *to, Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag); +/* + * User/group ID to name translation. + */ +int can_get_users_groups_by_id(struct sftp_conn *conn); +int do_get_users_groups_by_id(struct sftp_conn *conn, + const u_int *uids, u_int nuids, + const u_int *gids, u_int ngids, + char ***usernamesp, char ***groupnamesp); + /* Concatenate paths, taking care of slashes. Caller must free result. */ char *path_append(const char *, const char *);