unix,win: add gecos field to uv_passwd_t
On Unix the gecos field usually contains the full name of the user. This is returned by getpwuid_r() on Unix and GetUserNameExW on Windows (falling back to NameSamCompatible if the users display name is not set). Co-authored-by: cjihrig <cjihrig@gmail.com> Co-authored-by: Saúl Ibarra Corretgé <saghul@gmail.com> Refs: https://github.com/libuv/libuv/pull/834 Fixes: https://github.com/libuv/libuv/issues/831 PR-URL: https://github.com/libuv/libuv/pull/1789 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
parent
884dd9f1be
commit
8eed38fd4a
@ -64,7 +64,7 @@ AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])
|
||||
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
|
||||
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
|
||||
AS_CASE([$host_os],[mingw*], [
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32"
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -lsecur32 -luserenv -luser32"
|
||||
])
|
||||
AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])])
|
||||
AC_CHECK_HEADERS([sys/ahafs_evProds.h])
|
||||
|
||||
@ -140,6 +140,7 @@ Data types
|
||||
long gid;
|
||||
char* shell;
|
||||
char* homedir;
|
||||
char* gecos;
|
||||
} uv_passwd_t;
|
||||
|
||||
|
||||
@ -422,6 +423,8 @@ API
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
.. versionchanged:: 2.0.0 `gecos` support is added.
|
||||
|
||||
.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd)
|
||||
|
||||
Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`.
|
||||
|
||||
@ -1096,6 +1096,7 @@ struct uv_passwd_s {
|
||||
long gid;
|
||||
char* shell;
|
||||
char* homedir;
|
||||
char* gecos;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@ -1155,6 +1155,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
size_t name_size;
|
||||
size_t homedir_size;
|
||||
size_t shell_size;
|
||||
size_t gecos_size;
|
||||
long initsize;
|
||||
int r;
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
@ -1203,11 +1204,24 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
return UV_ENOENT;
|
||||
}
|
||||
|
||||
/* Allocate memory for the username, shell, and home directory */
|
||||
/* Allocate memory for the username, gecos, shell, and home directory. */
|
||||
name_size = strlen(pw.pw_name) + 1;
|
||||
homedir_size = strlen(pw.pw_dir) + 1;
|
||||
shell_size = strlen(pw.pw_shell) + 1;
|
||||
pwd->username = uv__malloc(name_size + homedir_size + shell_size);
|
||||
|
||||
#ifdef __MVS__
|
||||
gecos_size = 0; /* pw_gecos does not exist on zOS. */
|
||||
#else
|
||||
if (pw.pw_gecos != NULL)
|
||||
gecos_size = strlen(pw.pw_gecos) + 1;
|
||||
else
|
||||
gecos_size = 0;
|
||||
#endif
|
||||
|
||||
pwd->username = uv__malloc(name_size +
|
||||
homedir_size +
|
||||
shell_size +
|
||||
gecos_size);
|
||||
|
||||
if (pwd->username == NULL) {
|
||||
uv__free(buf);
|
||||
@ -1225,6 +1239,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
pwd->shell = pwd->homedir + homedir_size;
|
||||
memcpy(pwd->shell, pw.pw_shell, shell_size);
|
||||
|
||||
/* Copy the gecos field */
|
||||
#ifdef __MVS__
|
||||
pwd->gecos = NULL; /* pw_gecos does not exist on zOS. */
|
||||
#else
|
||||
if (pw.pw_gecos == NULL) {
|
||||
pwd->gecos = NULL;
|
||||
} else {
|
||||
pwd->gecos = pwd->shell + shell_size;
|
||||
memcpy(pwd->gecos, pw.pw_gecos, gecos_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copy the uid and gid */
|
||||
pwd->uid = pw.pw_uid;
|
||||
pwd->gid = pw.pw_gid;
|
||||
@ -1240,7 +1266,7 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
return;
|
||||
|
||||
/*
|
||||
The memory for name, shell, and homedir are allocated in a single
|
||||
The memory for name, shell, homedir, and gecos 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.
|
||||
*/
|
||||
@ -1248,6 +1274,7 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
pwd->username = NULL;
|
||||
pwd->shell = NULL;
|
||||
pwd->homedir = NULL;
|
||||
pwd->gecos = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -35,6 +35,9 @@
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#include <security.h>
|
||||
|
||||
|
||||
/*
|
||||
* Max title length; the only thing MSDN tells us about the maximum length
|
||||
@ -1169,8 +1172,10 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
|
||||
uv__free(pwd->username);
|
||||
uv__free(pwd->homedir);
|
||||
uv__free(pwd->gecos);
|
||||
pwd->username = NULL;
|
||||
pwd->homedir = NULL;
|
||||
pwd->gecos = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -1275,6 +1280,9 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
wchar_t username[UNLEN + 1];
|
||||
wchar_t path[MAX_PATH];
|
||||
DWORD bufsize;
|
||||
wchar_t* gecosbuf;
|
||||
ULONG gecos_size;
|
||||
EXTENDED_NAME_FORMAT name_format;
|
||||
int r;
|
||||
|
||||
if (pwd == NULL)
|
||||
@ -1310,18 +1318,60 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
/* Set all of the pointers to NULL in case an error is encountered. */
|
||||
pwd->homedir = NULL;
|
||||
pwd->username = NULL;
|
||||
pwd->gecos = NULL;
|
||||
gecosbuf = NULL;
|
||||
|
||||
/* Get the gecos using GetUserNameExW() */
|
||||
gecos_size = 0;
|
||||
/* Try using the display name first. */
|
||||
GetUserNameExW(NameDisplay, NULL, &gecos_size);
|
||||
if (GetLastError() == ERROR_MORE_DATA) {
|
||||
name_format = NameDisplay;
|
||||
} else {
|
||||
/* NameDisplay not available, so try NameSamCompatible. */
|
||||
GetUserNameExW(NameSamCompatible, NULL, &gecos_size);
|
||||
if (GetLastError() == ERROR_MORE_DATA) {
|
||||
name_format = NameSamCompatible;
|
||||
} else {
|
||||
/* Unsupported */
|
||||
gecos_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gecos_size > 0) {
|
||||
gecosbuf = uv__malloc(sizeof(wchar_t) * gecos_size);
|
||||
if (gecosbuf == NULL) {
|
||||
r = UV_ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (GetUserNameExW(name_format, gecosbuf, &gecos_size) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the uv_passwd_t structure. */
|
||||
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
goto error;
|
||||
|
||||
pwd->username = NULL;
|
||||
r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
|
||||
|
||||
if (r != 0) {
|
||||
uv__free(pwd->homedir);
|
||||
return r;
|
||||
if (r != 0)
|
||||
goto error;
|
||||
|
||||
if (gecosbuf != NULL) {
|
||||
r = uv__convert_utf16_to_utf8(gecosbuf, -1, &pwd->gecos);
|
||||
|
||||
if (r != 0)
|
||||
goto error;
|
||||
|
||||
uv__free(gecosbuf);
|
||||
}
|
||||
|
||||
pwd->shell = NULL;
|
||||
@ -1329,6 +1379,13 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
pwd->gid = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv__free(gecosbuf);
|
||||
uv__free(pwd->homedir);
|
||||
uv__free(pwd->username);
|
||||
uv__free(pwd->gecos);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -70,6 +70,7 @@ TEST_IMPL(get_passwd) {
|
||||
ASSERT(pwd.username == NULL);
|
||||
ASSERT(pwd.shell == NULL);
|
||||
ASSERT(pwd.homedir == NULL);
|
||||
ASSERT(pwd.gecos == NULL);
|
||||
|
||||
/* Test a double free */
|
||||
uv_os_free_passwd(&pwd);
|
||||
@ -77,6 +78,7 @@ TEST_IMPL(get_passwd) {
|
||||
ASSERT(pwd.username == NULL);
|
||||
ASSERT(pwd.shell == NULL);
|
||||
ASSERT(pwd.homedir == NULL);
|
||||
ASSERT(pwd.gecos == NULL);
|
||||
|
||||
/* Test invalid input */
|
||||
r = uv_os_get_passwd(NULL);
|
||||
|
||||
@ -145,6 +145,7 @@ TEST_IMPL(platform_output) {
|
||||
printf(" username: %s\n", pwd.username);
|
||||
printf(" shell: %s\n", pwd.shell);
|
||||
printf(" home directory: %s\n", pwd.homedir);
|
||||
printf(" gecos: %s\n", pwd.gecos);
|
||||
|
||||
pid = uv_os_getpid();
|
||||
ASSERT(pid > 0);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user