From: VMware, Inc <> Date: Wed, 17 Apr 2013 19:22:31 +0000 (-0700) Subject: Split /etc/passwd & /etc/group related methods from posixPosix.c X-Git-Tag: 2013.04.16-1098359~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=096ad5143bf9aad8aefec43ae023f11c35d89494;p=thirdparty%2Fopen-vm-tools.git Split /etc/passwd & /etc/group related methods from posixPosix.c It makes monitor linker a bit smaller, and it avoids warnings about linking program using get{pw,gr}* statically. It is mechanical change spliting posixPosix.c into two pieces. And simplifying includes in posixPwd.c... Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/lib/misc/Makefile.am b/open-vm-tools/lib/misc/Makefile.am index e26c143aa..aedfcdaa5 100644 --- a/open-vm-tools/lib/misc/Makefile.am +++ b/open-vm-tools/lib/misc/Makefile.am @@ -41,6 +41,7 @@ libMisc_la_SOURCES += msgfmt.c libMisc_la_SOURCES += msgList.c libMisc_la_SOURCES += posixDlopen.c libMisc_la_SOURCES += posixPosix.c +libMisc_la_SOURCES += posixPwd.c libMisc_la_SOURCES += random.c libMisc_la_SOURCES += timeutil.c libMisc_la_SOURCES += util_misc.c diff --git a/open-vm-tools/lib/misc/posixPosix.c b/open-vm-tools/lib/misc/posixPosix.c index 95933b1d3..6b3ded238 100644 --- a/open-vm-tools/lib/misc/posixPosix.c +++ b/open-vm-tools/lib/misc/posixPosix.c @@ -16,10 +16,6 @@ * *********************************************************/ -#if !defined(_POSIX_PTHREAD_SEMANTICS) && defined(sun) -#define _POSIX_PTHREAD_SEMANTICS 1 // Needed to get POSIX-correct getpw*_r() on Solaris -#endif - #define UNICODE_BUILDING_POSIX_WRAPPERS #if __linux__ @@ -39,8 +35,6 @@ #include #include #include -#include -#include #if defined(__APPLE__) #include @@ -85,16 +79,11 @@ #include "vm_basic_defs.h" -static struct passwd *GetpwInternal(struct passwd *pw); -static int GetpwInternal_r(struct passwd *pw, char *buf, size_t size, - struct passwd **ppw); - #if defined __ANDROID__ /* - * Android doesn't support getmntent_r(), getpwent() or setmntent(). + * Android doesn't support getmntent_r() or setmntent(). */ #define NO_GETMNTENT_R -#define NO_GETPWENT #define NO_SETMNTENT EXTERN int truncate(const char *, off_t); @@ -1595,166 +1584,6 @@ Posix_Putenv(Unicode name) // IN: } -/* - *---------------------------------------------------------------------- - * - * Posix_Getpwnam -- - * - * POSIX getpwnam() - * - * Results: - * Pointer to updated passwd struct on NULL on error. - * - * Side effects: - * errno is set on error - * - *---------------------------------------------------------------------- - */ - -struct passwd * -Posix_Getpwnam(ConstUnicode name) // IN: -{ - struct passwd *pw; - char *tmpname; - - if (!PosixConvertToCurrent(name, &tmpname)) { - return NULL; - } - pw = getpwnam(tmpname); - free(tmpname); - - return GetpwInternal(pw); -} - - -/* - *---------------------------------------------------------------------- - * - * Posix_Getpwuid -- - * - * POSIX getpwuid() - * - * Results: - * Pointer to updated passwd struct on NULL on error. - * - * Side effects: - * errno is set on error - * - *---------------------------------------------------------------------- - */ - -struct passwd * -Posix_Getpwuid(uid_t uid) // IN: -{ - struct passwd *pw = getpwuid(uid); - - return GetpwInternal(pw); -} - - -/* - *---------------------------------------------------------------------- - * - * GetpwInternal -- - * - * Helper function for Posix_Getpwnam, Posix_Getpwuid and Posix_Getpwent - * - * Results: - * Pointer to updated passwd struct on NULL on error. - * - * Side effects: - * errno is set on error - * - *---------------------------------------------------------------------- - */ - -static struct passwd * -GetpwInternal(struct passwd *pw) // IN: -{ - int ret; - static struct passwd spw = {0}; - - if (!pw) { - return NULL; - } - - /* Free static structure string pointers before reuse. */ - free(spw.pw_passwd); - spw.pw_passwd = NULL; - free(spw.pw_dir); - spw.pw_dir = NULL; - free(spw.pw_name); - spw.pw_name = NULL; -#if !defined __ANDROID__ - free(spw.pw_gecos); - spw.pw_gecos = NULL; -#endif - free(spw.pw_shell); - spw.pw_shell = NULL; -#if defined(__FreeBSD__) - free(spw.pw_class); - spw.pw_class = NULL; -#endif - - /* Fill out structure with new values. */ - spw.pw_uid = pw->pw_uid; - spw.pw_gid = pw->pw_gid; -#if defined(__FreeBSD__) - spw.pw_change = pw->pw_change; - spw.pw_expire = pw->pw_expire; - spw.pw_fields = pw->pw_fields; -#endif - -#if !defined(sun) - ret = ENOMEM; -#else - ret = EIO; -#endif - if (pw->pw_passwd && - (spw.pw_passwd = Unicode_Alloc(pw->pw_passwd, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (pw->pw_dir && - (spw.pw_dir = Unicode_Alloc(pw->pw_dir, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (pw->pw_name && - (spw.pw_name = Unicode_Alloc(pw->pw_name, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#if !defined __ANDROID__ - if (pw->pw_gecos && - (spw.pw_gecos = Unicode_Alloc(pw->pw_gecos, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#endif - if (pw->pw_shell && - (spw.pw_shell = Unicode_Alloc(pw->pw_shell, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#if defined(__FreeBSD__) - if (pw->pw_class && - (spw.pw_class = Unicode_Alloc(pw->pw_class, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#endif - ret = 0; - -exit: - if (ret != 0) { - errno = ret; - return NULL; - } - return &spw; -} - - #if !defined(sun) // { /* @@ -1914,907 +1743,6 @@ Posix_Unsetenv(ConstUnicode name) // IN: } -/*---------------------------------------------------------------------- - * Posix_Getpwent -- - * - * POSIX getpwent() - * - * Results: - * Pointer to updated passwd struct or NULL on error. - * - * Side effects: - * errno is set on error - * - *---------------------------------------------------------------------- - */ - -struct passwd * -Posix_Getpwent(void) -{ -#if defined NO_GETPWENT - NOT_IMPLEMENTED(); - errno = ENOSYS; - return NULL; -#else - struct passwd *pw = getpwent(); - - return GetpwInternal(pw); -#endif -} - -#if !defined(VM_SYSTEM_HAS_GETPWNAM_R) || \ - !defined(VM_SYSTEM_HAS_GETPWUID_R) || \ - !defined(VM_SYSTEM_HAS_GETGRNAM_R) // { -/* - *----------------------------------------------------------------------------- - * - * CopyFieldIntoBuf -- - * - * Copies a field in a passwd/group structure into the supplied buffer, - * and sets that pointer into dest. Used as a helper function for the - * EmulateGet* routines. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * Updates *buf and *bufLen to allocate space for the copied field. - * - *----------------------------------------------------------------------------- - */ - -static Bool -CopyFieldIntoBuf(const char *src, // IN: - char **dest, // OUT: - char **buf, // OUT - size_t *bufLen) // OUT: -{ - if (src) { - size_t needLen = strlen(src) + 1; - - if (*bufLen < needLen) { - return FALSE; - } - - *dest = *buf; - memcpy(*dest, src, needLen); - *buf += needLen; - *bufLen -= needLen; - } else { - *dest = NULL; - } - - return TRUE; -} - - -#endif // } - - -#if !defined(VM_SYSTEM_HAS_GETPWNAM_R) || !defined(VM_SYSTEM_HAS_GETPWUID_R) // { -/* - *----------------------------------------------------------------------------- - * - * PasswdCopy -- - * - * Copies a password structure as part of emulating the getpw*_r routines. - * - * Results: - * 'new' if successful, NULL otherwise. - * - * Side effects: - * Modifies 'buf' - * - *----------------------------------------------------------------------------- - */ - -static struct passwd * -PasswdCopy(struct passwd *orig, // IN - struct passwd *new, // IN/OUT - char *buf, // IN - size_t bufLen) // IN -{ - if (!orig) { - return NULL; - } - - *new = *orig; - - if (!CopyFieldIntoBuf(orig->pw_name, &new->pw_name, &buf, &bufLen)) { - return NULL; - } - if (!CopyFieldIntoBuf(orig->pw_passwd, &new->pw_passwd, &buf, &bufLen)) { - return NULL; - } -#if !defined __ANDROID__ - if (!CopyFieldIntoBuf(orig->pw_gecos, &new->pw_gecos, &buf, &bufLen)) { - return NULL; - } -#endif - if (!CopyFieldIntoBuf(orig->pw_dir, &new->pw_dir, &buf, &bufLen)) { - return NULL; - } - if (!CopyFieldIntoBuf(orig->pw_shell, &new->pw_shell, &buf, &bufLen)) { - return NULL; - } -#ifdef __FreeBSD__ - if (!CopyFieldIntoBuf(orig->pw_class, &new->pw_class, &buf, &bufLen)) { - return NULL; - } -#endif - - return new; -} -#endif // } - - -#ifndef VM_SYSTEM_HAS_GETPWNAM_R // { -/* - *----------------------------------------------------------------------------- - * - * EmulateGetpwnam_r -- - * - * Emulates getpwnam_r() for old/odd systems that don't have it - * - * Results: - * None. - * - * Side effects: - * Data may be stored in 'buf'. - * - *----------------------------------------------------------------------------- - */ - -static int -EmulateGetpwnam_r(const char *name, // IN - struct passwd *pwbuf, // IN/OUT - char *buf, // IN - size_t buflen, // IN - struct passwd **pwbufp) // IN/OUT -{ - static Atomic_uint32 mutex = {0}; - struct passwd *pw; - int savedErrno; - - ASSERT(pwbuf); - ASSERT(name); - ASSERT(buf); - ASSERT(pwbufp); - - /* - * XXX Use YIELD() here when it works on FreeBSD. - */ - while (Atomic_ReadWrite(&mutex, 1)); // Spinlock. - - pw = getpwnam(name); - savedErrno = errno; - *pwbufp = PasswdCopy(pw, pwbuf, buf, buflen); - - Atomic_Write(&mutex, 0); - - if (pw) { - return 0; - } else if (savedErrno) { - return savedErrno; - } else { - return ENOENT; - } -} -#endif - - -#ifndef VM_SYSTEM_HAS_GETPWUID_R -/* - *----------------------------------------------------------------------------- - * - * EmulateGetpwuid_r -- - * - * Emulates getpwuid_r() for old/odd systems that don't have it - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -EmulateGetpwuid_r(uid_t uid, // IN: - struct passwd *pwbuf, // IN/OUT: - char *buf, // IN: - size_t buflen, // IN: - struct passwd **pwbufp) // IN/OUT: -{ - static Atomic_uint32 mutex = {0}; - struct passwd *pw; - int savedErrno; - - ASSERT(pwbuf); - ASSERT(buf); - ASSERT(pwbufp); - - /* - * XXX Use YIELD() here when it works on FreeBSD. - */ - - while (Atomic_ReadWrite(&mutex, 1)); // Spinlock - - pw = getpwuid(uid); - savedErrno = errno; - *pwbufp = PasswdCopy(pw, pwbuf, buf, buflen); - - Atomic_Write(&mutex, 0); - - if (pw) { - return 0; - } else if (savedErrno) { - return savedErrno; - } else { - return ENOENT; - } -} -#endif // } - - -#ifndef VM_SYSTEM_HAS_GETGRNAM_R // { -/* - *----------------------------------------------------------------------------- - * - * GroupCopy -- - * - * Copies a password structure as part of emulating the getgr*_r routines. - * - * Results: - * 'new' if successful, NULL otherwise. - * - * Side effects: - * Modifies 'buf' - * - *----------------------------------------------------------------------------- - */ - -static struct group * -GroupCopy(struct group *orig, // IN: - struct group *new, // IN/OUT: - char *buf, // IN: - size_t bufLen) // IN: -{ - if (!orig) { - return NULL; - } - - *new = *orig; - - if (!CopyFieldIntoBuf(orig->gr_name, &new->gr_name, &buf, &bufLen)) { - return NULL; - } - if (!CopyFieldIntoBuf(orig->gr_passwd, &new->gr_passwd, &buf, &bufLen)) { - return NULL; - } - - if (orig->gr_mem) { - int i; - uintptr_t alignLen; - char **newGrMem; - - /* - * Before putting the gr_mem 'char **' array into 'buf', aligns the - * buffer to a pointer-size boundary. - */ - - alignLen = ((((uintptr_t) buf) + - (sizeof(void *) - 1)) & ~(sizeof(void *) - 1)); - alignLen -= ((uintptr_t) buf); - - if (bufLen < alignLen) { - return NULL; - } - buf += alignLen; - bufLen -= alignLen; - - /* - * Count the number of items in the gr_mem array, and then copy them all. - */ - - for (i = 0; orig->gr_mem[i]; i++); - i++; // need space for a terminating NULL - - if (bufLen < (i * sizeof(void *))) { - return NULL; - } - newGrMem = (char **)buf; - buf += i * sizeof(void *); - bufLen -= i * sizeof(void *); - - for (i = 0; orig->gr_mem[i]; i++, newGrMem++) { - size_t flen; - - flen = strlen(orig->gr_mem[i]) + 1; - if (bufLen < flen) { - return NULL; - } - - *newGrMem = buf; - memcpy(*newGrMem, orig->gr_mem[i], flen); - buf += flen; - bufLen -= flen; - } - *newGrMem = NULL; - } - - return new; -} -#endif // } - - -#ifndef VM_SYSTEM_HAS_GETGRNAM_R // { -/* - *----------------------------------------------------------------------------- - * - * EmulateGetgrnam_r -- - * - * Emulates getgrnam_r() for old/odd systems that don't have it - * - * Results: - * None. - * - * Side effects: - * Data may be stored in 'buf'. - * - *----------------------------------------------------------------------------- - */ - -static int -EmulateGetgrnam_r(const char *name, // IN: - struct group *grbuf, // IN/OUT: - char *buf, // IN: - size_t buflen, // IN: - struct group **grbufp) // IN/OUT: -{ - static Atomic_uint32 mutex = {0}; - struct group *gr; - int savedErrno; - - ASSERT(grbuf); - ASSERT(name); - ASSERT(buf); - ASSERT(grbufp); - - /* - * XXX Use YIELD() here once it is available on FreeBSD - */ - - while (Atomic_ReadWrite(&mutex, 1)); // Spinlock - - gr = getgrnam(name); - savedErrno = errno; - *grbufp = GroupCopy(gr, grbuf, buf, buflen); - - Atomic_Write(&mutex, 0); - - if (gr) { - return 0; - } else if (savedErrno) { - return savedErrno; - } else { - return ENOENT; - } -} -#endif // } - - -/* - *---------------------------------------------------------------------- - * - * Posix_Getpwnam_r -- - * - * POSIX getpwnam_r() - * - * Results: - * Returns 0 with success and pointer to updated passwd struct - * or returns error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Posix_Getpwnam_r(ConstUnicode name, // IN: - struct passwd *pw, // IN: - char *buf, // IN: - size_t size, // IN: - struct passwd **ppw) // OUT: -{ - int ret; - char *tmpname; - - if (!PosixConvertToCurrent(name, &tmpname)) { - /* - * Act like nonexistent user, almost. - * While getpwnam_r() returns 0 on nonexistent user, - * we will return the errno instead. - */ - - *ppw = NULL; - - return errno; - } - -#if defined(VM_SYSTEM_HAS_GETPWNAM_R) - ret = getpwnam_r(tmpname, pw, buf, size, ppw); -#else - ret = EmulateGetpwnam_r(tmpname, pw, buf, size, ppw); -#endif - - free(tmpname); - - // ret is errno on failure, *ppw is NULL if no matching entry found. - if (ret != 0 || *ppw == NULL) { - return ret; - } - - return GetpwInternal_r(pw, buf, size, ppw); -} - - -/* - *---------------------------------------------------------------------- - * - * Posix_Getpwuid_r -- - * - * POSIX getpwuid_r() - * - * Results: - * Returns 0 with success and pointer to updated passwd struct - * or returns error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Posix_Getpwuid_r(uid_t uid, // IN: - struct passwd *pw, // IN: - char *buf, // IN: - size_t size, // IN: - struct passwd **ppw) // OUT: -{ - int ret; - -#if defined(VM_SYSTEM_HAS_GETPWNAM_R) - ret = getpwuid_r(uid, pw, buf, size, ppw); -#else - ret = EmulateGetpwuid_r(uid, pw, buf, size, ppw); -#endif - if (ret != 0 || *ppw == NULL) { - // ret is errno on failure, *ppw is NULL if no matching entry found. - return ret; - } - - return GetpwInternal_r(pw, buf, size, ppw); -} - - -/* - *---------------------------------------------------------------------- - * - * GetpwInternal_r -- - * - * Helper function for Posix_Getpwnam_r and Posix_Getpwuid_r - * - * Results: - * Returns 0 with success and pointer to updated passwd struct - * or returns error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -GetpwInternal_r(struct passwd *pw, // IN: - char *buf, // IN: - size_t size, // IN: - struct passwd **ppw) // OUT: -{ - int ret; - char *pwname = NULL; - char *passwd = NULL; -#if !defined __ANDROID__ - char *gecos = NULL; -#endif - char *dir = NULL; - char *shell = NULL; - size_t n; - - /* - * Maybe getpwnam_r didn't use supplied struct, but we don't care. - * We just fix up the one it gives us. - */ - - pw = *ppw; - - /* - * Convert strings to UTF-8 - */ - - ret = ENOMEM; - if (pw->pw_name && - (pwname = Unicode_Alloc(pw->pw_name, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (pw->pw_passwd && - (passwd = Unicode_Alloc(pw->pw_passwd, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#if !defined __ANDROID__ - if (pw->pw_gecos && - (gecos = Unicode_Alloc(pw->pw_gecos, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } -#endif - if (pw->pw_dir && - (dir = Unicode_Alloc(pw->pw_dir, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (pw->pw_shell && - (shell = Unicode_Alloc(pw->pw_shell, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - - /* - * Put UTF-8 strings into the structure. - */ - - ret = ERANGE; - n = 0; - - if (pwname) { - size_t len = strlen(pwname) + 1; - - if (n + len > size || n + len < n) { - goto exit; - } - pw->pw_name = memcpy(buf + n, pwname, len); - n += len; - } - - if (passwd != NULL) { - size_t len = strlen(passwd) + 1; - - if (n + len > size || n + len < n) { - goto exit; - } - pw->pw_passwd = memcpy(buf + n, passwd, len); - n += len; - } -#if !defined __ANDROID__ - if (gecos) { - size_t len = strlen(gecos) + 1; - - if (n + len > size || n + len < n) { - goto exit; - } - pw->pw_gecos = memcpy(buf + n, gecos, len); - n += len; - } -#endif - if (dir) { - size_t len = strlen(dir) + 1; - - if (n + len > size || n + len < n) { - goto exit; - } - pw->pw_dir = memcpy(buf + n, dir, len); - n += len; - } - - if (shell) { - size_t len = strlen(shell) + 1; - - if (n + len > size || n + len < n) { - goto exit; - } - pw->pw_shell = memcpy(buf + n, shell, len); - n += len; - } - ret = 0; - -exit: - free(passwd); - free(dir); - free(pwname); -#if !defined __ANDROID__ - free(gecos); -#endif - free(shell); - - return ret; -} - - -#if !defined(sun) // { -/* - *---------------------------------------------------------------------- - * - * Posix_GetGroupList -- - * - * POSIX getgrouplist() - * - * Results: - * Returns number of groups found, or -1 if *ngroups is - * smaller than number of groups found. Also returns - * the list of groups. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Posix_GetGroupList(ConstUnicode user, // IN: - gid_t group, // IN: - gid_t *groups, // OUT: - int *ngroups) // IN/OUT: -{ - char *tmpuser; - int ret; - - if (!PosixConvertToCurrent(user, &tmpuser)) { - /* - * Act like nonexistent user. - * The supplied gid is always returned, so there's exactly - * one group. - * While the man page doesn't say, the return value is - * the same as *ngroups in the success case. - * - * Should we always return -1 instead? - * - * -- edward - */ - - int n = *ngroups; - - *ngroups = 1; - if (n < 1) { - return -1; - } - ASSERT(groups != NULL); - *groups = group; - - return 1; - } - - ret = getgrouplist(tmpuser, group, groups, ngroups); - - free(tmpuser); - - return ret; -} - - -#endif // } - -/* - *---------------------------------------------------------------------- - * Posix_Getgrnam -- - * - * POSIX getgrnam() - * - * Results: - * Pointer to updated group struct on NULL on error. - * - * Side effects: - * errno is set on error - * - *---------------------------------------------------------------------- - */ - -struct group * -Posix_Getgrnam(ConstUnicode name) // IN: -{ - struct group *gr; - char *tmpname; - int ret; - static struct group sgr = {0}; - - if (!PosixConvertToCurrent(name, &tmpname)) { - return NULL; - } - gr = getgrnam(tmpname); - free(tmpname); - - if (!gr) { - return NULL; - } - - /* Free static structure string pointers before reuse. */ - free(sgr.gr_name); - sgr.gr_name = NULL; - free(sgr.gr_passwd); - sgr.gr_passwd = NULL; - if (sgr.gr_mem != NULL) { - Unicode_FreeList(sgr.gr_mem, -1); - sgr.gr_mem = NULL; - } - - /* Fill out structure with new values. */ - sgr.gr_gid = gr->gr_gid; - - ret = ENOMEM; - if (gr->gr_passwd && - (sgr.gr_passwd = Unicode_Alloc(gr->gr_passwd, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (gr->gr_name && - (sgr.gr_name = Unicode_Alloc(gr->gr_name, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (gr->gr_mem) { - sgr.gr_mem = Unicode_AllocList(gr->gr_mem, -1, - STRING_ENCODING_DEFAULT); - } - - ret = 0; - - exit: - if (ret != 0) { - errno = ret; - return NULL; - } - - return &sgr; -} - - -/* - *---------------------------------------------------------------------- - * - * Posix_Getgrnam_r -- - * - * POSIX getgrnam_r() - * - * Results: - * Returns 0 with success and pointer to updated group struct - * or returns error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Posix_Getgrnam_r(ConstUnicode name, // IN: - struct group *gr, // IN: - char *buf, // IN: - size_t size, // IN: - struct group **pgr) // OUT: -{ - int ret, i; - char *tmpname; - char *grname = NULL; - char *grpasswd = NULL; - char **grmem = NULL; - size_t n; - - if (!PosixConvertToCurrent(name, &tmpname)) { - /* - * Act like nonexistent group, almost. - * While getgrnam_r() returns 0 on nonexistent group, - * we will return the errno instead. - */ - - *pgr = NULL; - - return errno; - } - -#if defined(VM_SYSTEM_HAS_GETGRNAM_R) - ret = getgrnam_r(tmpname, gr, buf, size, pgr); -#else - ret = EmulateGetgrnam_r(tmpname, gr, buf, size, pgr); -#endif - free(tmpname); - - // ret is errno on failure, *pgr is NULL if no matching entry found. - if (ret != 0 || *pgr == NULL) { - return ret; - } - - /* - * Maybe getgrnam_r didn't use supplied struct, but we don't care. - * We just fix up the one it gives us. - */ - - gr = *pgr; - - /* - * Convert strings to UTF-8 - */ - - ret = ENOMEM; - if (gr->gr_name && - (grname = Unicode_Alloc(gr->gr_name, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (gr->gr_passwd && - (grpasswd = Unicode_Alloc(gr->gr_passwd, - STRING_ENCODING_DEFAULT)) == NULL) { - goto exit; - } - if (gr->gr_mem) { - grmem = Unicode_AllocList(gr->gr_mem, -1, STRING_ENCODING_DEFAULT); - } - - /* - * Put UTF-8 strings into the structure. - */ - - ret = ERANGE; - n = 0; - - if (grname) { - size_t len = strlen(grname) + 1; - - if (n + len > size) { - goto exit; - } - gr->gr_name = memcpy(buf + n, grname, len); - n += len; - } - - if (grpasswd != NULL) { - size_t len = strlen(grpasswd) + 1; - - if (n + len > size) { - goto exit; - } - gr->gr_passwd = memcpy(buf + n, grpasswd, len); - n += len; - } - - if (grmem) { - for (i = 0; grmem[i]; i++) { - size_t len = strlen(grmem[i]) + 1; - - if (n + len > size) { - goto exit; - } - gr->gr_mem[i] = memcpy(buf + n, grmem[i], len); - n += len; - } - } - - ret = 0; - - exit: - free(grpasswd); - free(grname); - if (grmem) { - Unicode_FreeList(grmem, -1); - } - - return ret; -} - - #if !defined(sun) // { #if !defined(__APPLE__) && !defined(__FreeBSD__) // { diff --git a/open-vm-tools/lib/misc/posixPwd.c b/open-vm-tools/lib/misc/posixPwd.c new file mode 100644 index 000000000..d621b8182 --- /dev/null +++ b/open-vm-tools/lib/misc/posixPwd.c @@ -0,0 +1,1108 @@ +/********************************************************* + * Copyright (C) 2008 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 2.1 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + *********************************************************/ + +#if !defined(_POSIX_PTHREAD_SEMANTICS) && defined(sun) +#define _POSIX_PTHREAD_SEMANTICS 1 // Needed to get POSIX-correct getpw*_r() on Solaris +#endif + +#define UNICODE_BUILDING_POSIX_WRAPPERS + +#include "vmware.h" +#include "posixInt.h" + +#include +#include + +#if (!defined(__FreeBSD__) || __FreeBSD_release >= 503001) && !defined __ANDROID__ +#define VM_SYSTEM_HAS_GETPWNAM_R 1 +#define VM_SYSTEM_HAS_GETPWUID_R 1 +#define VM_SYSTEM_HAS_GETGRNAM_R 1 +#endif + +static struct passwd *GetpwInternal(struct passwd *pw); +static int GetpwInternal_r(struct passwd *pw, char *buf, size_t size, + struct passwd **ppw); + +#if defined __ANDROID__ +/* + * Android doesn't support getpwent(). + */ +#define NO_GETPWENT +#endif + + +/* + *---------------------------------------------------------------------- + * + * Posix_Getpwnam -- + * + * POSIX getpwnam() + * + * Results: + * Pointer to updated passwd struct on NULL on error. + * + * Side effects: + * errno is set on error + * + *---------------------------------------------------------------------- + */ + +struct passwd * +Posix_Getpwnam(ConstUnicode name) // IN: +{ + struct passwd *pw; + char *tmpname; + + if (!PosixConvertToCurrent(name, &tmpname)) { + return NULL; + } + pw = getpwnam(tmpname); + free(tmpname); + + return GetpwInternal(pw); +} + + +/* + *---------------------------------------------------------------------- + * + * Posix_Getpwuid -- + * + * POSIX getpwuid() + * + * Results: + * Pointer to updated passwd struct on NULL on error. + * + * Side effects: + * errno is set on error + * + *---------------------------------------------------------------------- + */ + +struct passwd * +Posix_Getpwuid(uid_t uid) // IN: +{ + struct passwd *pw = getpwuid(uid); + + return GetpwInternal(pw); +} + + +/* + *---------------------------------------------------------------------- + * + * GetpwInternal -- + * + * Helper function for Posix_Getpwnam, Posix_Getpwuid and Posix_Getpwent + * + * Results: + * Pointer to updated passwd struct on NULL on error. + * + * Side effects: + * errno is set on error + * + *---------------------------------------------------------------------- + */ + +static struct passwd * +GetpwInternal(struct passwd *pw) // IN: +{ + int ret; + static struct passwd spw = {0}; + + if (!pw) { + return NULL; + } + + /* Free static structure string pointers before reuse. */ + free(spw.pw_passwd); + spw.pw_passwd = NULL; + free(spw.pw_dir); + spw.pw_dir = NULL; + free(spw.pw_name); + spw.pw_name = NULL; +#if !defined __ANDROID__ + free(spw.pw_gecos); + spw.pw_gecos = NULL; +#endif + free(spw.pw_shell); + spw.pw_shell = NULL; +#if defined(__FreeBSD__) + free(spw.pw_class); + spw.pw_class = NULL; +#endif + + /* Fill out structure with new values. */ + spw.pw_uid = pw->pw_uid; + spw.pw_gid = pw->pw_gid; +#if defined(__FreeBSD__) + spw.pw_change = pw->pw_change; + spw.pw_expire = pw->pw_expire; + spw.pw_fields = pw->pw_fields; +#endif + +#if !defined(sun) + ret = ENOMEM; +#else + ret = EIO; +#endif + if (pw->pw_passwd && + (spw.pw_passwd = Unicode_Alloc(pw->pw_passwd, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (pw->pw_dir && + (spw.pw_dir = Unicode_Alloc(pw->pw_dir, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (pw->pw_name && + (spw.pw_name = Unicode_Alloc(pw->pw_name, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#if !defined __ANDROID__ + if (pw->pw_gecos && + (spw.pw_gecos = Unicode_Alloc(pw->pw_gecos, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#endif + if (pw->pw_shell && + (spw.pw_shell = Unicode_Alloc(pw->pw_shell, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#if defined(__FreeBSD__) + if (pw->pw_class && + (spw.pw_class = Unicode_Alloc(pw->pw_class, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#endif + ret = 0; + +exit: + if (ret != 0) { + errno = ret; + return NULL; + } + return &spw; +} + + +/* + *---------------------------------------------------------------------- + * Posix_Getpwent -- + * + * POSIX getpwent() + * + * Results: + * Pointer to updated passwd struct or NULL on error. + * + * Side effects: + * errno is set on error + * + *---------------------------------------------------------------------- + */ + +struct passwd * +Posix_Getpwent(void) +{ +#if defined NO_GETPWENT + NOT_IMPLEMENTED(); + errno = ENOSYS; + return NULL; +#else + struct passwd *pw = getpwent(); + + return GetpwInternal(pw); +#endif +} + +#if !defined(VM_SYSTEM_HAS_GETPWNAM_R) || \ + !defined(VM_SYSTEM_HAS_GETPWUID_R) || \ + !defined(VM_SYSTEM_HAS_GETGRNAM_R) // { +/* + *----------------------------------------------------------------------------- + * + * CopyFieldIntoBuf -- + * + * Copies a field in a passwd/group structure into the supplied buffer, + * and sets that pointer into dest. Used as a helper function for the + * EmulateGet* routines. + * + * Results: + * TRUE on success, FALSE on failure. + * + * Side effects: + * Updates *buf and *bufLen to allocate space for the copied field. + * + *----------------------------------------------------------------------------- + */ + +static Bool +CopyFieldIntoBuf(const char *src, // IN: + char **dest, // OUT: + char **buf, // OUT + size_t *bufLen) // OUT: +{ + if (src) { + size_t needLen = strlen(src) + 1; + + if (*bufLen < needLen) { + return FALSE; + } + + *dest = *buf; + memcpy(*dest, src, needLen); + *buf += needLen; + *bufLen -= needLen; + } else { + *dest = NULL; + } + + return TRUE; +} + + +#endif // } + + +#if !defined(VM_SYSTEM_HAS_GETPWNAM_R) || !defined(VM_SYSTEM_HAS_GETPWUID_R) // { +/* + *----------------------------------------------------------------------------- + * + * PasswdCopy -- + * + * Copies a password structure as part of emulating the getpw*_r routines. + * + * Results: + * 'new' if successful, NULL otherwise. + * + * Side effects: + * Modifies 'buf' + * + *----------------------------------------------------------------------------- + */ + +static struct passwd * +PasswdCopy(struct passwd *orig, // IN + struct passwd *new, // IN/OUT + char *buf, // IN + size_t bufLen) // IN +{ + if (!orig) { + return NULL; + } + + *new = *orig; + + if (!CopyFieldIntoBuf(orig->pw_name, &new->pw_name, &buf, &bufLen)) { + return NULL; + } + if (!CopyFieldIntoBuf(orig->pw_passwd, &new->pw_passwd, &buf, &bufLen)) { + return NULL; + } +#if !defined __ANDROID__ + if (!CopyFieldIntoBuf(orig->pw_gecos, &new->pw_gecos, &buf, &bufLen)) { + return NULL; + } +#endif + if (!CopyFieldIntoBuf(orig->pw_dir, &new->pw_dir, &buf, &bufLen)) { + return NULL; + } + if (!CopyFieldIntoBuf(orig->pw_shell, &new->pw_shell, &buf, &bufLen)) { + return NULL; + } +#ifdef __FreeBSD__ + if (!CopyFieldIntoBuf(orig->pw_class, &new->pw_class, &buf, &bufLen)) { + return NULL; + } +#endif + + return new; +} +#endif // } + + +#ifndef VM_SYSTEM_HAS_GETPWNAM_R // { +/* + *----------------------------------------------------------------------------- + * + * EmulateGetpwnam_r -- + * + * Emulates getpwnam_r() for old/odd systems that don't have it + * + * Results: + * None. + * + * Side effects: + * Data may be stored in 'buf'. + * + *----------------------------------------------------------------------------- + */ + +static int +EmulateGetpwnam_r(const char *name, // IN + struct passwd *pwbuf, // IN/OUT + char *buf, // IN + size_t buflen, // IN + struct passwd **pwbufp) // IN/OUT +{ + static Atomic_uint32 mutex = {0}; + struct passwd *pw; + int savedErrno; + + ASSERT(pwbuf); + ASSERT(name); + ASSERT(buf); + ASSERT(pwbufp); + + /* + * XXX Use YIELD() here when it works on FreeBSD. + */ + while (Atomic_ReadWrite(&mutex, 1)); // Spinlock. + + pw = getpwnam(name); + savedErrno = errno; + *pwbufp = PasswdCopy(pw, pwbuf, buf, buflen); + + Atomic_Write(&mutex, 0); + + if (pw) { + return 0; + } else if (savedErrno) { + return savedErrno; + } else { + return ENOENT; + } +} +#endif + + +#ifndef VM_SYSTEM_HAS_GETPWUID_R +/* + *----------------------------------------------------------------------------- + * + * EmulateGetpwuid_r -- + * + * Emulates getpwuid_r() for old/odd systems that don't have it + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +EmulateGetpwuid_r(uid_t uid, // IN: + struct passwd *pwbuf, // IN/OUT: + char *buf, // IN: + size_t buflen, // IN: + struct passwd **pwbufp) // IN/OUT: +{ + static Atomic_uint32 mutex = {0}; + struct passwd *pw; + int savedErrno; + + ASSERT(pwbuf); + ASSERT(buf); + ASSERT(pwbufp); + + /* + * XXX Use YIELD() here when it works on FreeBSD. + */ + + while (Atomic_ReadWrite(&mutex, 1)); // Spinlock + + pw = getpwuid(uid); + savedErrno = errno; + *pwbufp = PasswdCopy(pw, pwbuf, buf, buflen); + + Atomic_Write(&mutex, 0); + + if (pw) { + return 0; + } else if (savedErrno) { + return savedErrno; + } else { + return ENOENT; + } +} +#endif // } + + +#ifndef VM_SYSTEM_HAS_GETGRNAM_R // { +/* + *----------------------------------------------------------------------------- + * + * GroupCopy -- + * + * Copies a password structure as part of emulating the getgr*_r routines. + * + * Results: + * 'new' if successful, NULL otherwise. + * + * Side effects: + * Modifies 'buf' + * + *----------------------------------------------------------------------------- + */ + +static struct group * +GroupCopy(struct group *orig, // IN: + struct group *new, // IN/OUT: + char *buf, // IN: + size_t bufLen) // IN: +{ + if (!orig) { + return NULL; + } + + *new = *orig; + + if (!CopyFieldIntoBuf(orig->gr_name, &new->gr_name, &buf, &bufLen)) { + return NULL; + } + if (!CopyFieldIntoBuf(orig->gr_passwd, &new->gr_passwd, &buf, &bufLen)) { + return NULL; + } + + if (orig->gr_mem) { + int i; + uintptr_t alignLen; + char **newGrMem; + + /* + * Before putting the gr_mem 'char **' array into 'buf', aligns the + * buffer to a pointer-size boundary. + */ + + alignLen = ((((uintptr_t) buf) + + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1)); + alignLen -= ((uintptr_t) buf); + + if (bufLen < alignLen) { + return NULL; + } + buf += alignLen; + bufLen -= alignLen; + + /* + * Count the number of items in the gr_mem array, and then copy them all. + */ + + for (i = 0; orig->gr_mem[i]; i++); + i++; // need space for a terminating NULL + + if (bufLen < (i * sizeof(void *))) { + return NULL; + } + newGrMem = (char **)buf; + buf += i * sizeof(void *); + bufLen -= i * sizeof(void *); + + for (i = 0; orig->gr_mem[i]; i++, newGrMem++) { + size_t flen; + + flen = strlen(orig->gr_mem[i]) + 1; + if (bufLen < flen) { + return NULL; + } + + *newGrMem = buf; + memcpy(*newGrMem, orig->gr_mem[i], flen); + buf += flen; + bufLen -= flen; + } + *newGrMem = NULL; + } + + return new; +} +#endif // } + + +#ifndef VM_SYSTEM_HAS_GETGRNAM_R // { +/* + *----------------------------------------------------------------------------- + * + * EmulateGetgrnam_r -- + * + * Emulates getgrnam_r() for old/odd systems that don't have it + * + * Results: + * None. + * + * Side effects: + * Data may be stored in 'buf'. + * + *----------------------------------------------------------------------------- + */ + +static int +EmulateGetgrnam_r(const char *name, // IN: + struct group *grbuf, // IN/OUT: + char *buf, // IN: + size_t buflen, // IN: + struct group **grbufp) // IN/OUT: +{ + static Atomic_uint32 mutex = {0}; + struct group *gr; + int savedErrno; + + ASSERT(grbuf); + ASSERT(name); + ASSERT(buf); + ASSERT(grbufp); + + /* + * XXX Use YIELD() here once it is available on FreeBSD + */ + + while (Atomic_ReadWrite(&mutex, 1)); // Spinlock + + gr = getgrnam(name); + savedErrno = errno; + *grbufp = GroupCopy(gr, grbuf, buf, buflen); + + Atomic_Write(&mutex, 0); + + if (gr) { + return 0; + } else if (savedErrno) { + return savedErrno; + } else { + return ENOENT; + } +} +#endif // } + + +/* + *---------------------------------------------------------------------- + * + * Posix_Getpwnam_r -- + * + * POSIX getpwnam_r() + * + * Results: + * Returns 0 with success and pointer to updated passwd struct + * or returns error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Posix_Getpwnam_r(ConstUnicode name, // IN: + struct passwd *pw, // IN: + char *buf, // IN: + size_t size, // IN: + struct passwd **ppw) // OUT: +{ + int ret; + char *tmpname; + + if (!PosixConvertToCurrent(name, &tmpname)) { + /* + * Act like nonexistent user, almost. + * While getpwnam_r() returns 0 on nonexistent user, + * we will return the errno instead. + */ + + *ppw = NULL; + + return errno; + } + +#if defined(VM_SYSTEM_HAS_GETPWNAM_R) + ret = getpwnam_r(tmpname, pw, buf, size, ppw); +#else + ret = EmulateGetpwnam_r(tmpname, pw, buf, size, ppw); +#endif + + free(tmpname); + + // ret is errno on failure, *ppw is NULL if no matching entry found. + if (ret != 0 || *ppw == NULL) { + return ret; + } + + return GetpwInternal_r(pw, buf, size, ppw); +} + + +/* + *---------------------------------------------------------------------- + * + * Posix_Getpwuid_r -- + * + * POSIX getpwuid_r() + * + * Results: + * Returns 0 with success and pointer to updated passwd struct + * or returns error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Posix_Getpwuid_r(uid_t uid, // IN: + struct passwd *pw, // IN: + char *buf, // IN: + size_t size, // IN: + struct passwd **ppw) // OUT: +{ + int ret; + +#if defined(VM_SYSTEM_HAS_GETPWNAM_R) + ret = getpwuid_r(uid, pw, buf, size, ppw); +#else + ret = EmulateGetpwuid_r(uid, pw, buf, size, ppw); +#endif + if (ret != 0 || *ppw == NULL) { + // ret is errno on failure, *ppw is NULL if no matching entry found. + return ret; + } + + return GetpwInternal_r(pw, buf, size, ppw); +} + + +/* + *---------------------------------------------------------------------- + * + * GetpwInternal_r -- + * + * Helper function for Posix_Getpwnam_r and Posix_Getpwuid_r + * + * Results: + * Returns 0 with success and pointer to updated passwd struct + * or returns error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +GetpwInternal_r(struct passwd *pw, // IN: + char *buf, // IN: + size_t size, // IN: + struct passwd **ppw) // OUT: +{ + int ret; + char *pwname = NULL; + char *passwd = NULL; +#if !defined __ANDROID__ + char *gecos = NULL; +#endif + char *dir = NULL; + char *shell = NULL; + size_t n; + + /* + * Maybe getpwnam_r didn't use supplied struct, but we don't care. + * We just fix up the one it gives us. + */ + + pw = *ppw; + + /* + * Convert strings to UTF-8 + */ + + ret = ENOMEM; + if (pw->pw_name && + (pwname = Unicode_Alloc(pw->pw_name, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (pw->pw_passwd && + (passwd = Unicode_Alloc(pw->pw_passwd, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#if !defined __ANDROID__ + if (pw->pw_gecos && + (gecos = Unicode_Alloc(pw->pw_gecos, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } +#endif + if (pw->pw_dir && + (dir = Unicode_Alloc(pw->pw_dir, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (pw->pw_shell && + (shell = Unicode_Alloc(pw->pw_shell, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + + /* + * Put UTF-8 strings into the structure. + */ + + ret = ERANGE; + n = 0; + + if (pwname) { + size_t len = strlen(pwname) + 1; + + if (n + len > size || n + len < n) { + goto exit; + } + pw->pw_name = memcpy(buf + n, pwname, len); + n += len; + } + + if (passwd != NULL) { + size_t len = strlen(passwd) + 1; + + if (n + len > size || n + len < n) { + goto exit; + } + pw->pw_passwd = memcpy(buf + n, passwd, len); + n += len; + } +#if !defined __ANDROID__ + if (gecos) { + size_t len = strlen(gecos) + 1; + + if (n + len > size || n + len < n) { + goto exit; + } + pw->pw_gecos = memcpy(buf + n, gecos, len); + n += len; + } +#endif + if (dir) { + size_t len = strlen(dir) + 1; + + if (n + len > size || n + len < n) { + goto exit; + } + pw->pw_dir = memcpy(buf + n, dir, len); + n += len; + } + + if (shell) { + size_t len = strlen(shell) + 1; + + if (n + len > size || n + len < n) { + goto exit; + } + pw->pw_shell = memcpy(buf + n, shell, len); + n += len; + } + ret = 0; + +exit: + free(passwd); + free(dir); + free(pwname); +#if !defined __ANDROID__ + free(gecos); +#endif + free(shell); + + return ret; +} + + +#if !defined(sun) // { +/* + *---------------------------------------------------------------------- + * + * Posix_GetGroupList -- + * + * POSIX getgrouplist() + * + * Results: + * Returns number of groups found, or -1 if *ngroups is + * smaller than number of groups found. Also returns + * the list of groups. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Posix_GetGroupList(ConstUnicode user, // IN: + gid_t group, // IN: + gid_t *groups, // OUT: + int *ngroups) // IN/OUT: +{ + char *tmpuser; + int ret; + + if (!PosixConvertToCurrent(user, &tmpuser)) { + /* + * Act like nonexistent user. + * The supplied gid is always returned, so there's exactly + * one group. + * While the man page doesn't say, the return value is + * the same as *ngroups in the success case. + * + * Should we always return -1 instead? + * + * -- edward + */ + + int n = *ngroups; + + *ngroups = 1; + if (n < 1) { + return -1; + } + ASSERT(groups != NULL); + *groups = group; + + return 1; + } + + ret = getgrouplist(tmpuser, group, groups, ngroups); + + free(tmpuser); + + return ret; +} + + +#endif // } + +/* + *---------------------------------------------------------------------- + * Posix_Getgrnam -- + * + * POSIX getgrnam() + * + * Results: + * Pointer to updated group struct on NULL on error. + * + * Side effects: + * errno is set on error + * + *---------------------------------------------------------------------- + */ + +struct group * +Posix_Getgrnam(ConstUnicode name) // IN: +{ + struct group *gr; + char *tmpname; + int ret; + static struct group sgr = {0}; + + if (!PosixConvertToCurrent(name, &tmpname)) { + return NULL; + } + gr = getgrnam(tmpname); + free(tmpname); + + if (!gr) { + return NULL; + } + + /* Free static structure string pointers before reuse. */ + free(sgr.gr_name); + sgr.gr_name = NULL; + free(sgr.gr_passwd); + sgr.gr_passwd = NULL; + if (sgr.gr_mem != NULL) { + Unicode_FreeList(sgr.gr_mem, -1); + sgr.gr_mem = NULL; + } + + /* Fill out structure with new values. */ + sgr.gr_gid = gr->gr_gid; + + ret = ENOMEM; + if (gr->gr_passwd && + (sgr.gr_passwd = Unicode_Alloc(gr->gr_passwd, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (gr->gr_name && + (sgr.gr_name = Unicode_Alloc(gr->gr_name, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (gr->gr_mem) { + sgr.gr_mem = Unicode_AllocList(gr->gr_mem, -1, + STRING_ENCODING_DEFAULT); + } + + ret = 0; + + exit: + if (ret != 0) { + errno = ret; + return NULL; + } + + return &sgr; +} + + +/* + *---------------------------------------------------------------------- + * + * Posix_Getgrnam_r -- + * + * POSIX getgrnam_r() + * + * Results: + * Returns 0 with success and pointer to updated group struct + * or returns error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Posix_Getgrnam_r(ConstUnicode name, // IN: + struct group *gr, // IN: + char *buf, // IN: + size_t size, // IN: + struct group **pgr) // OUT: +{ + int ret, i; + char *tmpname; + char *grname = NULL; + char *grpasswd = NULL; + char **grmem = NULL; + size_t n; + + if (!PosixConvertToCurrent(name, &tmpname)) { + /* + * Act like nonexistent group, almost. + * While getgrnam_r() returns 0 on nonexistent group, + * we will return the errno instead. + */ + + *pgr = NULL; + + return errno; + } + +#if defined(VM_SYSTEM_HAS_GETGRNAM_R) + ret = getgrnam_r(tmpname, gr, buf, size, pgr); +#else + ret = EmulateGetgrnam_r(tmpname, gr, buf, size, pgr); +#endif + free(tmpname); + + // ret is errno on failure, *pgr is NULL if no matching entry found. + if (ret != 0 || *pgr == NULL) { + return ret; + } + + /* + * Maybe getgrnam_r didn't use supplied struct, but we don't care. + * We just fix up the one it gives us. + */ + + gr = *pgr; + + /* + * Convert strings to UTF-8 + */ + + ret = ENOMEM; + if (gr->gr_name && + (grname = Unicode_Alloc(gr->gr_name, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (gr->gr_passwd && + (grpasswd = Unicode_Alloc(gr->gr_passwd, + STRING_ENCODING_DEFAULT)) == NULL) { + goto exit; + } + if (gr->gr_mem) { + grmem = Unicode_AllocList(gr->gr_mem, -1, STRING_ENCODING_DEFAULT); + } + + /* + * Put UTF-8 strings into the structure. + */ + + ret = ERANGE; + n = 0; + + if (grname) { + size_t len = strlen(grname) + 1; + + if (n + len > size) { + goto exit; + } + gr->gr_name = memcpy(buf + n, grname, len); + n += len; + } + + if (grpasswd != NULL) { + size_t len = strlen(grpasswd) + 1; + + if (n + len > size) { + goto exit; + } + gr->gr_passwd = memcpy(buf + n, grpasswd, len); + n += len; + } + + if (grmem) { + for (i = 0; grmem[i]; i++) { + size_t len = strlen(grmem[i]) + 1; + + if (n + len > size) { + goto exit; + } + gr->gr_mem[i] = memcpy(buf + n, grmem[i], len); + n += len; + } + } + + ret = 0; + + exit: + free(grpasswd); + free(grname); + if (grmem) { + Unicode_FreeList(grmem, -1); + } + + return ret; +}