upstream: sftp-server(8): add a "users-groups-by-id@openssh.com"

extension request that allows the client to obtain user/group names that
correspond to a set of uids/gids.

Will be used to make directory listings more useful and consistent
in sftp(1).

ok markus@

OpenBSD-Commit-ID: 7ebabde0bcb95ef949c4840fe89e697e30df47d3
This commit is contained in:
djm@openbsd.org 2022-09-19 10:40:52 +00:00 committed by Damien Miller
parent 231a346c0c
commit 74b77f7497
No known key found for this signature in database
2 changed files with 103 additions and 2 deletions

View File

@ -635,6 +635,47 @@ This request is identical to the "home-directory" request documented in:
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
@ -671,4 +712,4 @@ master instance and later clients.
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 $

View File

@ -1,4 +1,4 @@
/* $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.
*
@ -37,6 +37,7 @@
#include <poll.h>
#endif
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -122,6 +123,7 @@ static void process_extended_limits(u_int32_t id);
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 {
@ -170,6 +172,8 @@ static const struct sftp_handler extended_handlers[] = {
{ "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 }
};
@ -728,6 +732,7 @@ process_init(void)
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);
@ -1713,6 +1718,61 @@ process_extended_home_directory(u_int32_t id)
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)
{