diff --git a/configure.ac b/configure.ac index 52fb8270..d019a9d0 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 03878d60..0346bd79 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -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`. diff --git a/include/uv.h b/include/uv.h index 7ca6ace7..373c47f1 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1096,6 +1096,7 @@ struct uv_passwd_s { long gid; char* shell; char* homedir; + char* gecos; }; typedef enum { diff --git a/src/unix/core.c b/src/unix/core.c index 03be41c0..0149b73e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -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; } diff --git a/src/win/util.c b/src/win/util.c index 2e0f8412..851b7365 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -35,6 +35,9 @@ #include #include +#define SECURITY_WIN32 +#include + /* * 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; } diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index 8e16fb83..49860dea 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -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); diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 4025fba5..70b82ea1 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -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); diff --git a/uv.gyp b/uv.gyp index f6e4c04e..0b5703f6 100644 --- a/uv.gyp +++ b/uv.gyp @@ -135,6 +135,7 @@ '-liphlpapi', '-lpsapi', '-lshell32', + '-lsecur32', '-luser32', '-luserenv', '-lws2_32'