X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=pwutil.c;h=548da4d2d85eaaf97f3cd860acc15442fcf1361e;hb=f3530d8198251b72d01da9a07b1fa518446ec0f0;hp=86ae0ab2b92ebd16bf71fd27c5c72dd8060e7685;hpb=a91c5f78701b90c47a08daa15569ef64c6194504;p=debian%2Fsudo diff --git a/pwutil.c b/pwutil.c index 86ae0ab..548da4d 100644 --- a/pwutil.c +++ b/pwutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2010 + * Copyright (c) 1996, 1998-2005, 2007-2011 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -63,7 +63,25 @@ static struct rbtree *grcache_bygid, *grcache_byname; static int cmp_pwuid __P((const void *, const void *)); static int cmp_pwnam __P((const void *, const void *)); static int cmp_grgid __P((const void *, const void *)); -static int cmp_grnam __P((const void *, const void *)); + +#define cmp_grnam cmp_pwnam + +#define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item))) + +struct cache_item { + unsigned int refcnt; + /* key */ + union { + uid_t uid; + gid_t gid; + char *name; + } k; + /* datum */ + union { + struct passwd *pw; + struct group *gr; + } d; +}; /* * Compare by uid. @@ -73,9 +91,9 @@ cmp_pwuid(v1, v2) const void *v1; const void *v2; { - const struct passwd *pw1 = (const struct passwd *) v1; - const struct passwd *pw2 = (const struct passwd *) v2; - return(pw1->pw_uid - pw2->pw_uid); + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return ci1->k.uid - ci2->k.uid; } /* @@ -86,9 +104,9 @@ cmp_pwnam(v1, v2) const void *v1; const void *v2; { - const struct passwd *pw1 = (const struct passwd *) v1; - const struct passwd *pw2 = (const struct passwd *) v2; - return(strcasecmp(pw1->pw_name, pw2->pw_name)); + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return strcmp(ci1->k.name, ci2->k.name); } #define FIELD_SIZE(src, name, size) \ @@ -109,16 +127,22 @@ do { \ } while (0) /* - * Dynamically allocate space for a struct password and the constituent parts - * that we care about. Fills in pw_passwd from shadow file. + * Dynamically allocate space for a struct item plus the key and data + * elements. If name is non-NULL it is used as the key, else the + * uid is the key. Fills in datum from struct password. + * + * We would like to fill in the encrypted password too but the + * call to the shadow function could overwrite the pw buffer (NIS). */ -static struct passwd * -sudo_pwdup(pw) +static struct cache_item * +make_pwitem(pw, name) const struct passwd *pw; + const char *name; { char *cp; const char *pw_shell; size_t nsize, psize, csize, gsize, dsize, ssize, total; + struct cache_item *item; struct passwd *newpw; /* If shell field is empty, expand to _PATH_BSHELL. */ @@ -127,7 +151,7 @@ sudo_pwdup(pw) /* Allocate in one big chunk for easy freeing. */ nsize = psize = csize = gsize = dsize = ssize = 0; - total = sizeof(struct passwd); + total = sizeof(struct cache_item) + sizeof(struct passwd); FIELD_SIZE(pw, pw_name, nsize); FIELD_SIZE(pw, pw_passwd, psize); #ifdef HAVE_LOGIN_CAP_H @@ -138,15 +162,19 @@ sudo_pwdup(pw) /* Treat shell specially since we expand "" -> _PATH_BSHELL */ ssize = strlen(pw_shell) + 1; total += ssize; + if (name != NULL) + total += strlen(name) + 1; - if ((cp = malloc(total)) == NULL) - return(NULL); - newpw = (struct passwd *) cp; + /* Allocate space for struct item, struct passwd and the strings. */ + if ((item = malloc(total)) == NULL) + return NULL; + cp = (char *) item + sizeof(struct cache_item); /* * Copy in passwd contents and make strings relative to space * at the end of the buffer. */ + newpw = (struct passwd *) cp; memcpy(newpw, pw, sizeof(struct passwd)); cp += sizeof(struct passwd); FIELD_COPY(pw, newpw, pw_name, nsize); @@ -159,8 +187,43 @@ sudo_pwdup(pw) /* Treat shell specially since we expand "" -> _PATH_BSHELL */ memcpy(cp, pw_shell, ssize); newpw->pw_shell = cp; + cp += ssize; + + /* Set key and datum. */ + if (name != NULL) { + memcpy(cp, name, strlen(name) + 1); + item->k.name = cp; + } else { + item->k.uid = pw->pw_uid; + } + item->d.pw = newpw; + item->refcnt = 1; + + return item; +} + +void +pw_addref(pw) + struct passwd *pw; +{ + ptr_to_item(pw)->refcnt++; +} + +static void +pw_delref_item(v) + void *v; +{ + struct cache_item *item = v; + + if (--item->refcnt == 0) + efree(item); +} - return(newpw); +void +pw_delref(pw) + struct passwd *pw; +{ + pw_delref_item(ptr_to_item(pw)); } /* @@ -171,13 +234,12 @@ struct passwd * sudo_getpwuid(uid) uid_t uid; { - struct passwd key, *pw; + struct cache_item key, *item; struct rbnode *node; - char *cp; - key.pw_uid = uid; + key.k.uid = uid; if ((node = rbfind(pwcache_byuid, &key)) != NULL) { - pw = (struct passwd *) node->data; + item = (struct cache_item *) node->data; goto done; } /* @@ -186,27 +248,26 @@ sudo_getpwuid(uid) #ifdef HAVE_SETAUTHDB aix_setauthdb(IDtouser(uid)); #endif - if ((pw = getpwuid(uid)) != NULL) { - pw = sudo_pwdup(pw); - cp = sudo_getepw(pw); /* get shadow password */ - if (pw->pw_passwd != NULL) - zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd)); - pw->pw_passwd = cp; - if (rbinsert(pwcache_byuid, (void *) pw) != NULL) - errorx(1, "unable to cache uid %lu (%s), already exists", - uid, pw->pw_name); + if ((key.d.pw = getpwuid(uid)) != NULL) { + item = make_pwitem(key.d.pw, NULL); + if (rbinsert(pwcache_byuid, item) != NULL) + errorx(1, "unable to cache uid %u (%s), already exists", + (unsigned int) uid, item->d.pw->pw_name); } else { - pw = emalloc(sizeof(*pw)); - zero_bytes(pw, sizeof(*pw)); - pw->pw_uid = uid; - if (rbinsert(pwcache_byuid, (void *) pw) != NULL) - errorx(1, "unable to cache uid %lu, already exists", uid); + item = emalloc(sizeof(*item)); + item->refcnt = 1; + item->k.uid = uid; + item->d.pw = NULL; + if (rbinsert(pwcache_byuid, item) != NULL) + errorx(1, "unable to cache uid %u, already exists", + (unsigned int) uid); } #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif done: - return(pw->pw_name != NULL ? pw : NULL); + item->refcnt++; + return item->d.pw; } /* @@ -217,14 +278,13 @@ struct passwd * sudo_getpwnam(name) const char *name; { - struct passwd key, *pw; + struct cache_item key, *item; struct rbnode *node; size_t len; - char *cp; - key.pw_name = (char *) name; + key.k.name = (char *) name; if ((node = rbfind(pwcache_byname, &key)) != NULL) { - pw = (struct passwd *) node->data; + item = (struct cache_item *) node->data; goto done; } /* @@ -233,31 +293,26 @@ sudo_getpwnam(name) #ifdef HAVE_SETAUTHDB aix_setauthdb((char *) name); #endif - if ((pw = getpwnam(name)) != NULL) { - pw = sudo_pwdup(pw); - cp = sudo_getepw(pw); /* get shadow password */ - if (pw->pw_passwd != NULL) - zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd)); - pw->pw_passwd = cp; - if (rbinsert(pwcache_byname, (void *) pw) != NULL) + if ((key.d.pw = getpwnam(name)) != NULL) { + item = make_pwitem(key.d.pw, name); + if (rbinsert(pwcache_byname, item) != NULL) errorx(1, "unable to cache user %s, already exists", name); } else { len = strlen(name) + 1; - cp = emalloc(sizeof(*pw) + len); - zero_bytes(cp, sizeof(*pw)); - pw = (struct passwd *) cp; - cp += sizeof(*pw); - memcpy(cp, name, len); - pw->pw_name = cp; - pw->pw_uid = (uid_t) -1; - if (rbinsert(pwcache_byname, (void *) pw) != NULL) + item = emalloc(sizeof(*item) + len); + item->refcnt = 1; + item->k.name = (char *) item + sizeof(*item); + memcpy(item->k.name, name, len); + item->d.pw = NULL; + if (rbinsert(pwcache_byname, item) != NULL) errorx(1, "unable to cache user %s, already exists", name); } #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif done: - return(pw->pw_uid != (uid_t) -1 ? pw : NULL); + item->refcnt++; + return item->d.pw; } /* @@ -268,119 +323,84 @@ sudo_fakepwnam(user, gid) const char *user; gid_t gid; { + struct cache_item *item; struct passwd *pw; struct rbnode *node; - size_t len; + size_t len, namelen; + int i; - len = strlen(user); - pw = emalloc(sizeof(struct passwd) + len + 1 /* pw_name */ + + namelen = strlen(user); + len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + - sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL)); - zero_bytes(pw, sizeof(struct passwd)); - pw->pw_uid = (uid_t) atoi(user + 1); - pw->pw_gid = gid; - pw->pw_name = (char *)pw + sizeof(struct passwd); - memcpy(pw->pw_name, user, len + 1); - pw->pw_passwd = pw->pw_name + len + 1; - memcpy(pw->pw_passwd, "*", 2); - pw->pw_gecos = pw->pw_passwd + 2; - pw->pw_gecos[0] = '\0'; - pw->pw_dir = pw->pw_gecos + 1; - memcpy(pw->pw_dir, "/", 2); - pw->pw_shell = pw->pw_dir + 2; - memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); - - /* Store by uid and by name, overwriting cached version. */ - if ((node = rbinsert(pwcache_byuid, pw)) != NULL) { - efree(node->data); - node->data = (void *) pw; - } - if ((node = rbinsert(pwcache_byname, pw)) != NULL) { - efree(node->data); - node->data = (void *) pw; - } - return(pw); -} - -/* - * Take a gid in string form "#123" and return a faked up group struct. - */ -struct group * -sudo_fakegrnam(group) - const char *group; -{ - struct group *gr; - struct rbnode *node; - size_t len; - - len = strlen(group); - gr = emalloc(sizeof(struct group) + len + 1); - zero_bytes(gr, sizeof(struct group)); - gr->gr_gid = (gid_t) atoi(group + 1); - gr->gr_name = (char *)gr + sizeof(struct group); - strlcpy(gr->gr_name, group, len + 1); - - /* Store by gid and by name, overwriting cached version. */ - if ((node = rbinsert(grcache_bygid, gr)) != NULL) { - efree(node->data); - node->data = (void *) gr; - } - if ((node = rbinsert(grcache_byname, gr)) != NULL) { - efree(node->data); - node->data = (void *) gr; + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); + + for (i = 0; i < 2; i++) { + item = emalloc(len); + zero_bytes(item, sizeof(*item) + sizeof(*pw)); + pw = (struct passwd *) ((char *)item + sizeof(*item)); + pw->pw_uid = (uid_t) atoi(user + 1); + pw->pw_gid = gid; + pw->pw_name = (char *)pw + sizeof(struct passwd); + memcpy(pw->pw_name, user, namelen + 1); + pw->pw_passwd = pw->pw_name + namelen + 1; + memcpy(pw->pw_passwd, "*", 2); + pw->pw_gecos = pw->pw_passwd + 2; + pw->pw_gecos[0] = '\0'; + pw->pw_dir = pw->pw_gecos + 1; + memcpy(pw->pw_dir, "/", 2); + pw->pw_shell = pw->pw_dir + 2; + memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); + + item->refcnt = 1; + item->d.pw = pw; + if (i == 0) { + /* Store by uid, overwriting cached version. */ + item->k.uid = pw->pw_uid; + if ((node = rbinsert(pwcache_byuid, item)) != NULL) { + pw_delref_item(node->data); + node->data = item; + } + } else { + /* Store by name, overwriting cached version. */ + item->k.name = pw->pw_name; + if ((node = rbinsert(pwcache_byname, item)) != NULL) { + pw_delref_item(node->data); + node->data = item; + } + } } - return(gr); + item->refcnt++; + return pw; } void sudo_setpwent() { setpwent(); - sudo_setspent(); if (pwcache_byuid == NULL) pwcache_byuid = rbcreate(cmp_pwuid); if (pwcache_byname == NULL) pwcache_byname = rbcreate(cmp_pwnam); } -#ifdef PURIFY -static void pw_free __P((void *)); - void sudo_freepwcache() { if (pwcache_byuid != NULL) { - rbdestroy(pwcache_byuid, pw_free); + rbdestroy(pwcache_byuid, pw_delref_item); pwcache_byuid = NULL; } if (pwcache_byname != NULL) { - rbdestroy(pwcache_byname, NULL); + rbdestroy(pwcache_byname, pw_delref_item); pwcache_byname = NULL; } } -static void -pw_free(v) - void *v; -{ - struct passwd *pw = (struct passwd *) v; - - if (pw->pw_passwd != NULL) { - zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd)); - efree(pw->pw_passwd); - } - efree(pw); -} -#endif /* PURIFY */ - void sudo_endpwent() { endpwent(); - sudo_endspent(); -#ifdef PURIFY sudo_freepwcache(); -#endif } /* @@ -391,35 +411,29 @@ cmp_grgid(v1, v2) const void *v1; const void *v2; { - const struct group *grp1 = (const struct group *) v1; - const struct group *grp2 = (const struct group *) v2; - return(grp1->gr_gid - grp2->gr_gid); + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return ci1->k.gid - ci2->k.gid; } /* - * Compare by group name. + * Dynamically allocate space for a struct item plus the key and data + * elements. If name is non-NULL it is used as the key, else the + * gid is the key. Fills in datum from struct group. */ -static int -cmp_grnam(v1, v2) - const void *v1; - const void *v2; -{ - const struct group *grp1 = (const struct group *) v1; - const struct group *grp2 = (const struct group *) v2; - return(strcasecmp(grp1->gr_name, grp2->gr_name)); -} - -struct group * -sudo_grdup(gr) +static struct cache_item * +make_gritem(gr, name) const struct group *gr; + const char *name; { char *cp; size_t nsize, psize, nmem, total, len; + struct cache_item *item; struct group *newgr; /* Allocate in one big chunk for easy freeing. */ nsize = psize = nmem = 0; - total = sizeof(struct group); + total = sizeof(struct cache_item) + sizeof(struct group); FIELD_SIZE(gr, gr_name, nsize); FIELD_SIZE(gr, gr_passwd, psize); if (gr->gr_mem) { @@ -428,16 +442,20 @@ sudo_grdup(gr) nmem++; total += sizeof(char *) * nmem; } - if ((cp = malloc(total)) == NULL) - return(NULL); - newgr = (struct group *)cp; + if (name != NULL) + total += strlen(name) + 1; + + if ((item = malloc(total)) == NULL) + return NULL; + cp = (char *) item + sizeof(struct cache_item); /* * Copy in group contents and make strings relative to space * at the end of the buffer. Note that gr_mem must come * immediately after struct group to guarantee proper alignment. */ - (void)memcpy(newgr, gr, sizeof(struct group)); + newgr = (struct group *)cp; + memcpy(newgr, gr, sizeof(struct group)); cp += sizeof(struct group); if (gr->gr_mem) { newgr->gr_mem = (char **)cp; @@ -453,7 +471,41 @@ sudo_grdup(gr) FIELD_COPY(gr, newgr, gr_passwd, psize); FIELD_COPY(gr, newgr, gr_name, nsize); - return(newgr); + /* Set key and datum. */ + if (name != NULL) { + memcpy(cp, name, strlen(name) + 1); + item->k.name = cp; + } else { + item->k.gid = gr->gr_gid; + } + item->d.gr = newgr; + item->refcnt = 1; + + return item; +} + +void +gr_addref(gr) + struct group *gr; +{ + ptr_to_item(gr)->refcnt++; +} + +static void +gr_delref_item(v) + void *v; +{ + struct cache_item *item = v; + + if (--item->refcnt == 0) + efree(item); +} + +void +gr_delref(gr) + struct group *gr; +{ + gr_delref_item(ptr_to_item(gr)); } /* @@ -463,31 +515,34 @@ struct group * sudo_getgrgid(gid) gid_t gid; { - struct group key, *gr; + struct cache_item key, *item; struct rbnode *node; - key.gr_gid = gid; + key.k.gid = gid; if ((node = rbfind(grcache_bygid, &key)) != NULL) { - gr = (struct group *) node->data; + item = (struct cache_item *) node->data; goto done; } /* * Cache group db entry if it exists or a negative response if not. */ - if ((gr = getgrgid(gid)) != NULL) { - gr = sudo_grdup(gr); - if (rbinsert(grcache_bygid, (void *) gr) != NULL) - errorx(1, "unable to cache gid %lu (%s), already exists", - gid, gr->gr_name); + if ((key.d.gr = getgrgid(gid)) != NULL) { + item = make_gritem(key.d.gr, NULL); + if (rbinsert(grcache_bygid, item) != NULL) + errorx(1, "unable to cache gid %u (%s), already exists", + (unsigned int) gid, key.d.gr->gr_name); } else { - gr = emalloc(sizeof(*gr)); - zero_bytes(gr, sizeof(*gr)); - gr->gr_gid = gid; - if (rbinsert(grcache_bygid, (void *) gr) != NULL) - errorx(1, "unable to cache gid %lu, already exists, gid"); + item = emalloc(sizeof(*item)); + item->refcnt = 1; + item->k.gid = gid; + item->d.gr = NULL; + if (rbinsert(grcache_bygid, item) != NULL) + errorx(1, "unable to cache gid %u, already exists", + (unsigned int) gid); } done: - return(gr->gr_name != NULL ? gr : NULL); + item->refcnt++; + return item->d.gr; } /* @@ -497,37 +552,81 @@ struct group * sudo_getgrnam(name) const char *name; { - struct group key, *gr; + struct cache_item key, *item; struct rbnode *node; size_t len; - char *cp; - key.gr_name = (char *) name; + key.k.name = (char *) name; if ((node = rbfind(grcache_byname, &key)) != NULL) { - gr = (struct group *) node->data; + item = (struct cache_item *) node->data; goto done; } /* * Cache group db entry if it exists or a negative response if not. */ - if ((gr = getgrnam(name)) != NULL) { - gr = sudo_grdup(gr); - if (rbinsert(grcache_byname, (void *) gr) != NULL) + if ((key.d.gr = getgrnam(name)) != NULL) { + item = make_gritem(key.d.gr, name); + if (rbinsert(grcache_byname, item) != NULL) errorx(1, "unable to cache group %s, already exists", name); } else { len = strlen(name) + 1; - cp = emalloc(sizeof(*gr) + len); - zero_bytes(cp, sizeof(*gr)); - gr = (struct group *) cp; - cp += sizeof(*gr); - memcpy(cp, name, len); - gr->gr_name = cp; - gr->gr_gid = (gid_t) -1; - if (rbinsert(grcache_byname, (void *) gr) != NULL) + item = emalloc(sizeof(*item) + len); + item->refcnt = 1; + item->k.name = (char *) item + sizeof(*item); + memcpy(item->k.name, name, len); + item->d.gr = NULL; + if (rbinsert(grcache_byname, item) != NULL) errorx(1, "unable to cache group %s, already exists", name); } done: - return(gr->gr_gid != (gid_t) -1 ? gr : NULL); + item->refcnt++; + return item->d.gr; +} + +/* + * Take a gid in string form "#123" and return a faked up group struct. + */ +struct group * +sudo_fakegrnam(group) + const char *group; +{ + struct cache_item *item; + struct group *gr; + struct rbnode *node; + size_t len, namelen; + int i; + + namelen = strlen(group); + len = sizeof(*item) + sizeof(*gr) + namelen + 1; + + for (i = 0; i < 2; i++) { + item = emalloc(len); + zero_bytes(item, sizeof(*item) + sizeof(*gr)); + gr = (struct group *) ((char *)item + sizeof(*item)); + gr->gr_gid = (gid_t) atoi(group + 1); + gr->gr_name = (char *)gr + sizeof(struct group); + memcpy(gr->gr_name, group, namelen + 1); + + item->refcnt = 1; + item->d.gr = gr; + if (i == 0) { + /* Store by gid, overwriting cached version. */ + item->k.gid = gr->gr_gid; + if ((node = rbinsert(grcache_bygid, item)) != NULL) { + gr_delref_item(node->data); + node->data = item; + } + } else { + /* Store by name, overwriting cached version. */ + item->k.name = gr->gr_name; + if ((node = rbinsert(grcache_byname, item)) != NULL) { + gr_delref_item(node->data); + node->data = item; + } + } + } + item->refcnt++; + return gr; } void @@ -540,28 +639,24 @@ sudo_setgrent() grcache_byname = rbcreate(cmp_grnam); } -#ifdef PURIFY void sudo_freegrcache() { if (grcache_bygid != NULL) { - rbdestroy(grcache_bygid, free); + rbdestroy(grcache_bygid, gr_delref_item); grcache_bygid = NULL; } if (grcache_byname != NULL) { - rbdestroy(grcache_byname, NULL); + rbdestroy(grcache_byname, gr_delref_item); grcache_byname = NULL; } } -#endif /* PURIFY */ void sudo_endgrent() { endgrent(); -#ifdef PURIFY sudo_freegrcache(); -#endif } int @@ -577,32 +672,41 @@ user_in_group(pw, group) int i; #endif struct group *grp; + int retval = FALSE; #ifdef HAVE_SETAUTHDB aix_setauthdb(pw->pw_name); #endif - grp = sudo_getgrnam(group); + /* A group name that begins with a '#' may be a gid. */ + if ((grp = sudo_getgrnam(group)) == NULL && *group == '#') + grp = sudo_getgrgid(atoi(group + 1)); #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif if (grp == NULL) - return(FALSE); + goto done; /* check against user's primary (passwd file) gid */ - if (grp->gr_gid == pw->pw_gid) - return(TRUE); + if (grp->gr_gid == pw->pw_gid) { + retval = TRUE; + goto done; + } #ifdef HAVE_MBR_CHECK_MEMBERSHIP /* If we are matching the invoking user use the stashed uuid. */ if (strcmp(pw->pw_name, user_name) == 0) { if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 && - mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) - return(TRUE); + mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) { + retval = TRUE; + goto done; + } } else { if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 && mbr_gid_to_uuid(grp->gr_gid, gu) == 0 && - mbr_check_membership(uu, gu, &ismember) == 0 && ismember) - return(TRUE); + mbr_check_membership(uu, gu, &ismember) == 0 && ismember) { + retval = TRUE; + goto done; + } } #else /* HAVE_MBR_CHECK_MEMBERSHIP */ # ifdef HAVE_GETGROUPS @@ -613,20 +717,27 @@ user_in_group(pw, group) if (user_ngroups > 0 && strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) { for (i = 0; i < user_ngroups; i++) { - if (grp->gr_gid == user_groups[i]) - return(TRUE); + if (grp->gr_gid == user_groups[i]) { + retval = TRUE; + goto done; + } } } else # endif /* HAVE_GETGROUPS */ { if (grp != NULL && grp->gr_mem != NULL) { for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) { - if (strcmp(*gr_mem, pw->pw_name) == 0) - return(TRUE); + if (strcmp(*gr_mem, pw->pw_name) == 0) { + retval = TRUE; + goto done; + } } } } #endif /* HAVE_MBR_CHECK_MEMBERSHIP */ - return(FALSE); +done: + if (grp != NULL) + gr_delref(grp); + return retval; }