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:
Kári Tristan Helgason 2016-04-15 22:37:44 +00:00 committed by cjihrig
parent 884dd9f1be
commit 8eed38fd4a
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
8 changed files with 101 additions and 9 deletions

View File

@ -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])

View File

@ -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`.

View File

@ -1096,6 +1096,7 @@ struct uv_passwd_s {
long gid;
char* shell;
char* homedir;
char* gecos;
};
typedef enum {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

1
uv.gyp
View File

@ -135,6 +135,7 @@
'-liphlpapi',
'-lpsapi',
'-lshell32',
'-lsecur32',
'-luser32',
'-luserenv',
'-lws2_32'