https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-extensions-00#section-5
+4.12. sftp: Extension request "users-groups-by-id@openssh.com"
+
+This request asks the server to returns user and/or group names that
+correspond to one or more IDs (e.g. as returned from a SSH_FXP_STAT
+request). This may be used by the client to provide usernames in
+directory listings.
+
+ byte SSH_FXP_EXTENDED
+ uint32 id
+ string "users-groups-by-id@openssh.com"
+ string uids
+ string gids
+
+Where "uids" and "gids" consists of one or more integer user or group
+identifiers:
+
+ uint32 id-0
+ ...
+
+The server will reply with a SSH_FXP_EXTENDED_REPLY:
+
+ byte SSH_FXP_EXTENDED_REPLY
+ string usernames
+ string groupnames
+
+Where "username" and "groupnames" consists of names in identical request
+order to "uids" and "gids" respectively:
+
+ string name-0
+ ...
+
+If a name cannot be identified for a given user or group ID, an empty
+string will be returned in its place.
+
+It is acceptable for either "uids" or "gids" to be an empty set, in
+which case the respective "usernames" or "groupnames" list will also
+be empty.
+
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
5. Miscellaneous changes
5.1 Public key format
OpenSSH extends the usual agent protocol. These changes are documented
in the PROTOCOL.agent file.
-$OpenBSD: PROTOCOL,v 1.46 2022/08/12 05:20:28 djm Exp $
+$OpenBSD: PROTOCOL,v 1.47 2022/09/19 10:40:52 djm Exp $
-/* $OpenBSD: sftp-server.c,v 1.142 2022/09/16 06:55:37 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.143 2022/09/19 10:40:52 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
#include <stdio.h>
#include <string.h>
#include <pwd.h>
+#include <grp.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
static void process_extended_expand(u_int32_t id);
static void process_extended_copy_data(u_int32_t id);
static void process_extended_home_directory(u_int32_t id);
+static void process_extended_get_users_groups_by_id(u_int32_t id);
static void process_extended(u_int32_t id);
struct sftp_handler {
{ "copy-data", "copy-data", 0, process_extended_copy_data, 1 },
{ "home-directory", "home-directory", 0,
process_extended_home_directory, 0 },
+ { "users-groups-by-id", "users-groups-by-id@openssh.com", 0,
+ process_extended_get_users_groups_by_id, 0 },
{ NULL, NULL, 0, NULL, 0 }
};
compose_extension(msg, "expand-path@openssh.com", "1");
compose_extension(msg, "copy-data", "1");
compose_extension(msg, "home-directory", "1");
+ compose_extension(msg, "users-groups-by-id@openssh.com", "1");
send_msg(msg);
sshbuf_free(msg);
free(username);
}
+static void
+process_extended_get_users_groups_by_id(u_int32_t id)
+{
+ struct passwd *user_pw;
+ struct group *gr;
+ struct sshbuf *uids, *gids, *usernames, *groupnames, *msg;
+ int r;
+ u_int n, nusers = 0, ngroups = 0;
+ const char *name;
+
+ if ((usernames = sshbuf_new()) == NULL ||
+ (groupnames = sshbuf_new()) == NULL ||
+ (msg = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ if ((r = sshbuf_froms(iqueue, &uids)) != 0 ||
+ (r = sshbuf_froms(iqueue, &gids)) != 0)
+ fatal_fr(r, "parse");
+ debug_f("uids len = %zu, gids len = %zu",
+ sshbuf_len(uids), sshbuf_len(gids));
+ while (sshbuf_len(uids) != 0) {
+ if ((r = sshbuf_get_u32(uids, &n)) != 0)
+ fatal_fr(r, "parse inner uid");
+ user_pw = getpwuid((uid_t)n);
+ name = user_pw == NULL ? "" : user_pw->pw_name;
+ debug3_f("uid %u => \"%s\"", n, name);
+ if ((r = sshbuf_put_cstring(usernames, name)) != 0)
+ fatal_fr(r, "assemble gid reply");
+ nusers++;
+ }
+ while (sshbuf_len(gids) != 0) {
+ if ((r = sshbuf_get_u32(gids, &n)) != 0)
+ fatal_fr(r, "parse inner gid");
+ gr = getgrgid((gid_t)n);
+ name = gr == NULL ? "" : gr->gr_name;
+ debug3_f("gid %u => \"%s\"", n, name);
+ if ((r = sshbuf_put_cstring(groupnames, name)) != 0)
+ fatal_fr(r, "assemble gid reply");
+ nusers++;
+ }
+ verbose("users-groups-by-id: %u users, %u groups", nusers, ngroups);
+
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_stringb(msg, usernames)) != 0 ||
+ (r = sshbuf_put_stringb(msg, groupnames)) != 0)
+ fatal_fr(r, "compose");
+ send_msg(msg);
+
+ sshbuf_free(uids);
+ sshbuf_free(gids);
+ sshbuf_free(usernames);
+ sshbuf_free(groupnames);
+ sshbuf_free(msg);
+}
+
static void
process_extended(u_int32_t id)
{