mirror of
https://github.com/libuv/libuv
synced 2025-03-28 21:13:16 +00:00
misc: extend getpw to take uid as an argument (#3523)
File system operations may return uid and gid values, which we may want to pretty-print. We already have the code for getting information for the current user, so just need to add a parameter to make it exposed for every user. We expose information about groups in a similar manner also.
This commit is contained in:
parent
7fd7e8264f
commit
2f110a50df
10
include/uv.h
10
include/uv.h
@ -245,6 +245,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_group_s uv_group_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
typedef struct uv_statfs_s uv_statfs_t;
|
||||
|
||||
@ -1139,6 +1140,12 @@ struct uv_passwd_s {
|
||||
char* homedir;
|
||||
};
|
||||
|
||||
struct uv_group_s {
|
||||
char* groupname;
|
||||
unsigned long gid;
|
||||
char** members;
|
||||
};
|
||||
|
||||
struct uv_utsname_s {
|
||||
char sysname[256];
|
||||
char release[256];
|
||||
@ -1219,6 +1226,9 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
|
||||
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
|
||||
UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
|
||||
UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
|
||||
UV_EXTERN int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid);
|
||||
UV_EXTERN int uv_os_get_group(uv_group_t* grp, uv_uid_t gid);
|
||||
UV_EXTERN void uv_os_free_group(uv_group_t* grp);
|
||||
UV_EXTERN uv_pid_t uv_os_getpid(void);
|
||||
UV_EXTERN uv_pid_t uv_os_getppid(void);
|
||||
|
||||
|
106
src/unix/core.c
106
src/unix/core.c
@ -41,12 +41,12 @@
|
||||
#include <sys/uio.h> /* writev */
|
||||
#include <sys/resource.h> /* getrusage */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __sun
|
||||
# include <sys/filio.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
@ -1097,8 +1097,8 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
if (r != UV_ENOENT)
|
||||
return r;
|
||||
|
||||
/* HOME is not set, so call uv__getpwuid_r() */
|
||||
r = uv__getpwuid_r(&pwd);
|
||||
/* HOME is not set, so call uv_os_get_passwd() */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
|
||||
if (r != 0) {
|
||||
return r;
|
||||
@ -1171,11 +1171,10 @@ return_buffer:
|
||||
}
|
||||
|
||||
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
static int uv__getpwuid_r(uv_passwd_t *pwd, uid_t uid) {
|
||||
struct passwd pw;
|
||||
struct passwd* result;
|
||||
char* buf;
|
||||
uid_t uid;
|
||||
size_t bufsize;
|
||||
size_t name_size;
|
||||
size_t homedir_size;
|
||||
@ -1185,8 +1184,6 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
if (pwd == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
uid = geteuid();
|
||||
|
||||
/* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
|
||||
* is frequently 1024 or 4096, so we can just use that directly. The pwent
|
||||
* will not usually be large. */
|
||||
@ -1245,24 +1242,93 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
if (pwd == NULL)
|
||||
return;
|
||||
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
|
||||
struct group gp;
|
||||
struct group* result;
|
||||
char* buf;
|
||||
char* gr_mem;
|
||||
size_t bufsize;
|
||||
size_t name_size;
|
||||
long members;
|
||||
size_t mem_size;
|
||||
int r;
|
||||
|
||||
/*
|
||||
The memory for name, shell, and homedir are allocated in a single
|
||||
uv__malloc() call. The base of the pointer is stored in pwd->username, so
|
||||
that is the field that needs to be freed.
|
||||
*/
|
||||
uv__free(pwd->username);
|
||||
pwd->username = NULL;
|
||||
pwd->shell = NULL;
|
||||
pwd->homedir = NULL;
|
||||
if (grp == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Calling sysconf(_SC_GETGR_R_SIZE_MAX) would get the suggested size, but it
|
||||
* is frequently 1024 or 4096, so we can just use that directly. The pwent
|
||||
* will not usually be large. */
|
||||
for (bufsize = 2000;; bufsize *= 2) {
|
||||
buf = uv__malloc(bufsize);
|
||||
|
||||
if (buf == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
do
|
||||
r = getgrgid_r(gid, &gp, buf, bufsize, &result);
|
||||
while (r == EINTR);
|
||||
|
||||
if (r != 0 || result == NULL)
|
||||
uv__free(buf);
|
||||
|
||||
if (r != ERANGE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
return UV__ERR(r);
|
||||
|
||||
if (result == NULL)
|
||||
return UV_ENOENT;
|
||||
|
||||
/* Allocate memory for the groupname and members. */
|
||||
name_size = strlen(gp.gr_name) + 1;
|
||||
members = 0;
|
||||
mem_size = sizeof(char*);
|
||||
for (r = 0; gp.gr_mem[r] != NULL; r++) {
|
||||
mem_size += strlen(gp.gr_mem[r]) + 1 + sizeof(char*);
|
||||
members++;
|
||||
}
|
||||
|
||||
gr_mem = uv__malloc(name_size + mem_size);
|
||||
if (gr_mem == NULL) {
|
||||
uv__free(buf);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
/* Copy the members */
|
||||
grp->members = (char**) gr_mem;
|
||||
grp->members[members] = NULL;
|
||||
gr_mem = (char*) &grp->members[members + 1];
|
||||
for (r = 0; r < members; r++) {
|
||||
grp->members[r] = gr_mem;
|
||||
strcpy(gr_mem, gp.gr_mem[r]);
|
||||
gr_mem += strlen(gr_mem) + 1;
|
||||
}
|
||||
assert(gr_mem == (char*)grp->members + mem_size);
|
||||
|
||||
/* Copy the groupname */
|
||||
grp->groupname = gr_mem;
|
||||
memcpy(grp->groupname, gp.gr_name, name_size);
|
||||
gr_mem += name_size;
|
||||
|
||||
/* Copy the gid */
|
||||
grp->gid = gp.gr_gid;
|
||||
|
||||
uv__free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
return uv__getpwuid_r(pwd);
|
||||
return uv__getpwuid_r(pwd, geteuid());
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
|
||||
return uv__getpwuid_r(pwd, uid);
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,7 +312,6 @@ size_t uv__thread_stack_size(void);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
FILE* uv__open_file(const char* path);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__search_path(const char* prog, char* buf, size_t* buflen);
|
||||
void uv__wait_children(uv_loop_t* loop);
|
||||
|
||||
|
@ -128,6 +128,39 @@ int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
if (pwd == NULL)
|
||||
return;
|
||||
|
||||
/* On unix, the memory for name, shell, and homedir are allocated in a single
|
||||
* uv__malloc() call. The base of the pointer is stored in pwd->username, so
|
||||
* that is the field that needs to be freed.
|
||||
*/
|
||||
uv__free(pwd->username);
|
||||
#ifdef _WIN32
|
||||
uv__free(pwd->homedir);
|
||||
#endif
|
||||
pwd->username = NULL;
|
||||
pwd->shell = NULL;
|
||||
pwd->homedir = NULL;
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_group(uv_group_t *grp) {
|
||||
if (grp == NULL)
|
||||
return;
|
||||
|
||||
/* The memory for is allocated in a single uv__malloc() call. The base of the
|
||||
* pointer is stored in grp->members, so that is the only field that needs to
|
||||
* be freed.
|
||||
*/
|
||||
uv__free(grp->members);
|
||||
grp->members = NULL;
|
||||
grp->groupname = NULL;
|
||||
}
|
||||
|
||||
|
||||
#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
|
||||
|
||||
size_t uv_handle_size(uv_handle_type type) {
|
||||
|
@ -269,7 +269,6 @@ void uv__util_init(void);
|
||||
|
||||
uint64_t uv__hrtime(unsigned int scale);
|
||||
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
|
||||
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
|
||||
|
||||
|
@ -999,8 +999,8 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
if (r != UV_ENOENT)
|
||||
return r;
|
||||
|
||||
/* USERPROFILE is not set, so call uv__getpwuid_r() */
|
||||
r = uv__getpwuid_r(&pwd);
|
||||
/* USERPROFILE is not set, so call uv_os_get_passwd() */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
|
||||
if (r != 0) {
|
||||
return r;
|
||||
@ -1087,17 +1087,6 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
if (pwd == NULL)
|
||||
return;
|
||||
|
||||
uv__free(pwd->username);
|
||||
uv__free(pwd->homedir);
|
||||
pwd->username = NULL;
|
||||
pwd->homedir = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts a UTF-16 string into a UTF-8 one. The resulting string is
|
||||
* null-terminated.
|
||||
@ -1194,7 +1183,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
}
|
||||
|
||||
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
static int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
HANDLE token;
|
||||
wchar_t username[UNLEN + 1];
|
||||
wchar_t *path;
|
||||
@ -1272,6 +1261,16 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
wchar_t* env;
|
||||
wchar_t* penv;
|
||||
|
@ -39,32 +39,32 @@ TEST_IMPL(get_passwd) {
|
||||
|
||||
/* Test the normal case */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
ASSERT(r == 0);
|
||||
ASSERT_EQ(r, 0);
|
||||
len = strlen(pwd.username);
|
||||
ASSERT(len > 0);
|
||||
ASSERT_GT(len, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
ASSERT_NULL(pwd.shell);
|
||||
#else
|
||||
len = strlen(pwd.shell);
|
||||
# ifndef __PASE__
|
||||
ASSERT(len > 0);
|
||||
ASSERT_GT(len, 0);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
len = strlen(pwd.homedir);
|
||||
ASSERT(len > 0);
|
||||
ASSERT_GT(len, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (len == 3 && pwd.homedir[1] == ':')
|
||||
ASSERT(pwd.homedir[2] == '\\');
|
||||
ASSERT_EQ(pwd.homedir[2], '\\');
|
||||
else
|
||||
ASSERT(pwd.homedir[len - 1] != '\\');
|
||||
ASSERT_NE(pwd.homedir[len - 1], '\\');
|
||||
#else
|
||||
if (len == 1)
|
||||
ASSERT(pwd.homedir[0] == '/');
|
||||
ASSERT_EQ(pwd.homedir[0], '/');
|
||||
else
|
||||
ASSERT(pwd.homedir[len - 1] != '/');
|
||||
ASSERT_NE(pwd.homedir[len - 1], '/');
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -95,7 +95,110 @@ TEST_IMPL(get_passwd) {
|
||||
|
||||
/* Test invalid input */
|
||||
r = uv_os_get_passwd(NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
ASSERT_EQ(r, UV_EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(get_passwd2) {
|
||||
/* TODO(gengjiawen): Fix test on QEMU. */
|
||||
#if defined(__QEMU__)
|
||||
RETURN_SKIP("Test does not currently work in QEMU");
|
||||
#endif
|
||||
|
||||
uv_passwd_t pwd;
|
||||
uv_passwd_t pwd2;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
/* Test the normal case */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
ASSERT_EQ(r, 0);
|
||||
|
||||
r = uv_os_get_passwd2(&pwd2, pwd.uid);
|
||||
|
||||
#ifdef _WIN32
|
||||
ASSERT_EQ(r, UV_ENOTSUP);
|
||||
|
||||
#else
|
||||
ASSERT_EQ(r, 0);
|
||||
ASSERT_EQ(pwd.uid, pwd2.uid);
|
||||
ASSERT_STR_EQ(pwd.username, pwd2.username);
|
||||
ASSERT_STR_EQ(pwd.shell, pwd2.shell);
|
||||
ASSERT_STR_EQ(pwd.homedir, pwd2.homedir);
|
||||
uv_os_free_passwd(&pwd2);
|
||||
|
||||
r = uv_os_get_passwd2(&pwd2, 0);
|
||||
ASSERT_EQ(r, 0);
|
||||
|
||||
len = strlen(pwd2.username);
|
||||
ASSERT_GT(len, 0);
|
||||
ASSERT_STR_EQ(pwd2.username, "root");
|
||||
|
||||
len = strlen(pwd2.homedir);
|
||||
ASSERT_GT(len, 0);
|
||||
|
||||
len = strlen(pwd2.shell);
|
||||
# ifndef __PASE__
|
||||
ASSERT_GT(len, 0);
|
||||
# endif
|
||||
|
||||
uv_os_free_passwd(&pwd2);
|
||||
#endif
|
||||
|
||||
uv_os_free_passwd(&pwd);
|
||||
|
||||
/* Test invalid input */
|
||||
r = uv_os_get_passwd2(NULL, pwd.uid);
|
||||
#ifdef _WIN32
|
||||
ASSERT_EQ(r, UV_ENOTSUP);
|
||||
#else
|
||||
ASSERT_EQ(r, UV_EINVAL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(get_group) {
|
||||
/* TODO(gengjiawen): Fix test on QEMU. */
|
||||
#if defined(__QEMU__)
|
||||
RETURN_SKIP("Test does not currently work in QEMU");
|
||||
#endif
|
||||
|
||||
uv_passwd_t pwd;
|
||||
uv_group_t grp;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
ASSERT_EQ(r, 0);
|
||||
|
||||
r = uv_os_get_group(&grp, pwd.gid);
|
||||
|
||||
#ifdef _WIN32
|
||||
ASSERT_EQ(r, UV_ENOTSUP);
|
||||
|
||||
#else
|
||||
ASSERT_EQ(r, 0);
|
||||
ASSERT_EQ(pwd.gid, grp.gid);
|
||||
|
||||
len = strlen(grp.groupname);
|
||||
ASSERT_GT(len, 0);
|
||||
|
||||
uv_os_free_group(&grp);
|
||||
#endif
|
||||
|
||||
uv_os_free_passwd(&pwd);
|
||||
|
||||
/* Test invalid input */
|
||||
r = uv_os_get_group(NULL, pwd.gid);
|
||||
#ifdef _WIN32
|
||||
ASSERT_EQ(r, UV_ENOTSUP);
|
||||
#else
|
||||
ASSERT_EQ(r, UV_EINVAL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -281,6 +281,8 @@ TEST_DECLARE (process_title_threadsafe)
|
||||
TEST_DECLARE (cwd_and_chdir)
|
||||
TEST_DECLARE (get_memory)
|
||||
TEST_DECLARE (get_passwd)
|
||||
TEST_DECLARE (get_passwd2)
|
||||
TEST_DECLARE (get_group)
|
||||
TEST_DECLARE (handle_fileno)
|
||||
TEST_DECLARE (homedir)
|
||||
TEST_DECLARE (tmpdir)
|
||||
@ -899,6 +901,8 @@ TASK_LIST_START
|
||||
TEST_ENTRY (get_memory)
|
||||
|
||||
TEST_ENTRY (get_passwd)
|
||||
TEST_ENTRY (get_passwd2)
|
||||
TEST_ENTRY (get_group)
|
||||
|
||||
TEST_ENTRY (get_loadavg)
|
||||
|
||||
|
@ -35,8 +35,10 @@ TEST_IMPL(platform_output) {
|
||||
uv_cpu_info_t* cpus;
|
||||
uv_interface_address_t* interfaces;
|
||||
uv_passwd_t pwd;
|
||||
uv_group_t grp;
|
||||
uv_utsname_t uname;
|
||||
unsigned par;
|
||||
char* const* member;
|
||||
int count;
|
||||
int i;
|
||||
int err;
|
||||
@ -147,15 +149,38 @@ TEST_IMPL(platform_output) {
|
||||
uv_free_interface_addresses(interfaces, count);
|
||||
|
||||
err = uv_os_get_passwd(&pwd);
|
||||
ASSERT(err == 0);
|
||||
ASSERT_EQ(err, 0);
|
||||
|
||||
err = uv_os_get_group(&grp, pwd.gid);
|
||||
#if defined(_WIN32)
|
||||
ASSERT_EQ(err, UV_ENOTSUP);
|
||||
ASSERT_EQ(pwd.uid, (unsigned long) -1);
|
||||
ASSERT_EQ(pwd.gid, (unsigned long) -1);
|
||||
(void) member;
|
||||
grp.groupname = "ENOTSUP";
|
||||
#else
|
||||
ASSERT_EQ(err, 0);
|
||||
ASSERT_EQ(pwd.gid, grp.gid);
|
||||
#endif
|
||||
|
||||
printf("uv_os_get_passwd:\n");
|
||||
printf(" euid: %ld\n", pwd.uid);
|
||||
printf(" gid: %ld\n", pwd.gid);
|
||||
printf(" gid: %ld (%s)\n", pwd.gid, grp.groupname);
|
||||
#if !defined(_WIN32)
|
||||
printf(" members: [");
|
||||
for (member = grp.members; *member != NULL; member++) {
|
||||
printf(" %s", *member);
|
||||
}
|
||||
printf(" ]\n");
|
||||
#endif
|
||||
printf(" username: %s\n", pwd.username);
|
||||
printf(" shell: %s\n", pwd.shell);
|
||||
if (pwd.shell != NULL) /* Not set on Windows */
|
||||
printf(" shell: %s\n", pwd.shell);
|
||||
printf(" home directory: %s\n", pwd.homedir);
|
||||
uv_os_free_passwd(&pwd);
|
||||
#if !defined(_WIN32)
|
||||
uv_os_free_group(&grp);
|
||||
#endif
|
||||
|
||||
pid = uv_os_getpid();
|
||||
ASSERT(pid > 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user