Merge commit 'upstream/1.7.6p1'
[debian/sudo] / match.c
diff --git a/match.c b/match.c
index fd60fdbd28edb54e0c9641247662d8d3fabe6603..ba299e19d94c7bf4d97573530250ad15844310fd 100644 (file)
--- a/match.c
+++ b/match.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2009
+ * Copyright (c) 1996, 1998-2005, 2007-2011
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
 #endif /* STDC_HEADERS */
 #ifdef HAVE_STRING_H
 # include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
 #endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 # include "nonunix.h"
 #endif /* USING_NONUNIX_GROUPS */
 
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: match.c,v 1.46 2009/05/27 00:49:07 millert Exp $";
-#endif /* lint */
-
 static struct member_list empty;
 
 static int command_matches_dir __P((char *, size_t));
@@ -151,7 +146,7 @@ _userlist_matches(pw, list)
        if (matched != UNSPEC)
            break;
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -160,7 +155,7 @@ userlist_matches(pw, list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_userlist_matches(pw, list));
+    return _userlist_matches(pw, list);
 }
 
 /*
@@ -175,76 +170,79 @@ _runaslist_matches(user_list, group_list)
 {
     struct member *m;
     struct alias *a;
-    int rval, matched = UNSPEC;
-
-    if (runas_gr != NULL) {
-       if (tq_empty(group_list))
-           return(DENY); /* group was specified but none in sudoers */
-       if (runas_pw != NULL && strcmp(runas_pw->pw_name, user_name) &&
-           tq_empty(user_list))
-           return(DENY); /* user was specified but none in sudoers */
-    }
-
-    if (tq_empty(user_list) && tq_empty(group_list))
-       return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
+    int rval;
+    int user_matched = UNSPEC;
+    int group_matched = UNSPEC;
 
     if (runas_pw != NULL) {
+       /* If no runas user or runas group listed in sudoers, use default. */
+       if (tq_empty(user_list) && tq_empty(group_list))
+           return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
+
        tq_foreach_rev(user_list, m) {
            switch (m->type) {
                case ALL:
-                   matched = !m->negated;
+                   user_matched = !m->negated;
                    break;
                case NETGROUP:
                    if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
-                       matched = !m->negated;
+                       user_matched = !m->negated;
                    break;
                case USERGROUP:
                    if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
-                       matched = !m->negated;
+                       user_matched = !m->negated;
                    break;
                case ALIAS:
                    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
                        rval = _runaslist_matches(&a->members, &empty);
                        if (rval != UNSPEC)
-                           matched = m->negated ? !rval : rval;
+                           user_matched = m->negated ? !rval : rval;
                        break;
                    }
                    /* FALLTHROUGH */
                case WORD:
                    if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
-                       matched = !m->negated;
+                       user_matched = !m->negated;
                    break;
            }
-           if (matched != UNSPEC)
+           if (user_matched != UNSPEC)
                break;
        }
     }
 
     if (runas_gr != NULL) {
+       if (user_matched == UNSPEC) {
+           if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
+               user_matched = ALLOW;   /* only changing group */
+       }
        tq_foreach_rev(group_list, m) {
            switch (m->type) {
                case ALL:
-                   matched = !m->negated;
+                   group_matched = !m->negated;
                    break;
                case ALIAS:
                    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
                        rval = _runaslist_matches(&a->members, &empty);
                        if (rval != UNSPEC)
-                           matched = m->negated ? !rval : rval;
+                           group_matched = m->negated ? !rval : rval;
                        break;
                    }
                    /* FALLTHROUGH */
                case WORD:
                    if (group_matches(m->name, runas_gr))
-                       matched = !m->negated;
+                       group_matched = !m->negated;
                    break;
            }
-           if (matched != UNSPEC)
+           if (group_matched != UNSPEC)
                break;
        }
     }
 
-    return(matched);
+    if (user_matched == DENY || group_matched == DENY)
+       return DENY;
+    if (user_matched == group_matched || runas_gr == NULL)
+       return user_matched;
+    return UNSPEC;
 }
 
 int
@@ -253,8 +251,8 @@ runaslist_matches(user_list, group_list)
     struct member_list *group_list;
 {
     alias_seqno++;
-    return(_runaslist_matches(user_list ? user_list : &empty,
-       group_list ? group_list : &empty));
+    return _runaslist_matches(user_list ? user_list : &empty,
+       group_list ? group_list : &empty);
 }
 
 /*
@@ -298,7 +296,7 @@ _hostlist_matches(list)
        if (matched != UNSPEC)
            break;
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -306,7 +304,7 @@ hostlist_matches(list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_hostlist_matches(list));
+    return _hostlist_matches(list);
 }
 
 /*
@@ -318,16 +316,14 @@ _cmndlist_matches(list)
     struct member_list *list;
 {
     struct member *m;
-    int rval, matched = UNSPEC;
+    int matched = UNSPEC;
 
     tq_foreach_rev(list, m) {
-       rval = cmnd_matches(m);
-       if (rval != UNSPEC) {
-           matched = m->negated ? !rval : rval;
+       matched = cmnd_matches(m);
+       if (matched != UNSPEC)
            break;
-       }
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -335,7 +331,7 @@ cmndlist_matches(list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_cmndlist_matches(list));
+    return _cmndlist_matches(list);
 }
 
 /*
@@ -368,7 +364,35 @@ cmnd_matches(m)
                matched = !m->negated;
            break;
     }
-    return(matched);
+    return matched;
+}
+
+static int
+command_args_match(sudoers_cmnd, sudoers_args)
+    char *sudoers_cmnd;
+    char *sudoers_args;
+{
+    int flags = 0;
+
+    /*
+     * If no args specified in sudoers, any user args are allowed.
+     * If the empty string is specified in sudoers, no user args are allowed.
+     */
+    if (!sudoers_args ||
+       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)))
+       return TRUE;
+    /*
+     * If args are specified in sudoers, they must match the user args.
+     * If running as sudoedit, all args are assumed to be paths.
+     */
+    if (sudoers_args) {
+       /* For sudoedit, all args are assumed to be pathnames. */
+       if (strcmp(sudoers_cmnd, "sudoedit") == 0)
+           flags = FNM_PATHNAME;
+       if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
+           return TRUE;
+    }
+    return FALSE;
 }
 
 /*
@@ -381,7 +405,7 @@ command_matches(sudoers_cmnd, sudoers_args)
     char *sudoers_args;
 {
     /* Check for pseudo-commands */
-    if (strchr(user_cmnd, '/') == NULL) {
+    if (sudoers_cmnd[0] != '/') {
        /*
         * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
         *  a) there are no args in sudoers OR
@@ -390,16 +414,13 @@ command_matches(sudoers_cmnd, sudoers_args)
         */
        if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
            strcmp(user_cmnd, "sudoedit") != 0)
-           return(FALSE);
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+           return FALSE;
+       if (command_args_match(sudoers_cmnd, sudoers_args)) {
            efree(safe_cmnd);
            safe_cmnd = estrdup(sudoers_cmnd);
-           return(TRUE);
+           return TRUE;
        } else
-           return(FALSE);
+           return FALSE;
     }
 
     if (has_meta(sudoers_cmnd)) {
@@ -408,10 +429,10 @@ command_matches(sudoers_cmnd, sudoers_args)
         * use glob(3) and/or fnmatch(3) to do the matching.
         */
        if (def_fast_glob)
-           return(command_matches_fnmatch(sudoers_cmnd, sudoers_args));
-       return(command_matches_glob(sudoers_cmnd, sudoers_args));
+           return command_matches_fnmatch(sudoers_cmnd, sudoers_args);
+       return command_matches_glob(sudoers_cmnd, sudoers_args);
     }
-    return(command_matches_normal(sudoers_cmnd, sudoers_args));
+    return command_matches_normal(sudoers_cmnd, sudoers_args);
 }
 
 static int
@@ -427,17 +448,14 @@ command_matches_fnmatch(sudoers_cmnd, sudoers_args)
      * else return false.
      */
     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
-       return(FALSE);
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+       return FALSE;
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        if (safe_cmnd)
            free(safe_cmnd);
        safe_cmnd = estrdup(user_cmnd);
-       return(TRUE);
+       return TRUE;
     } else
-       return(FALSE);
+       return FALSE;
 }
 
 static int
@@ -460,7 +478,7 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
        if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
            base++;
            if (!has_meta(base) && strcmp(user_base, base) != 0)
-               return(FALSE);
+               return FALSE;
        }
     }
     /*
@@ -471,9 +489,9 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
      * else return false.
      */
 #define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
-    if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0) {
+    if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) {
        globfree(&gl);
-       return(FALSE);
+       return FALSE;
     }
     /* For each glob match, compare basename, st_dev and st_ino. */
     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
@@ -481,7 +499,7 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
        dlen = strlen(cp);
        if (cp[dlen - 1] == '/') {
            if (command_matches_dir(cp, dlen))
-               return(TRUE);
+               return TRUE;
            continue;
        }
 
@@ -503,17 +521,14 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
     }
     globfree(&gl);
     if (cp == NULL)
-       return(FALSE);
+       return FALSE;
 
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        efree(safe_cmnd);
        safe_cmnd = estrdup(user_cmnd);
-       return(TRUE);
+       return TRUE;
     }
-    return(FALSE);
+    return FALSE;
 }
 
 static int
@@ -528,7 +543,7 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
     /* If it ends in '/' it is a directory spec. */
     dlen = strlen(sudoers_cmnd);
     if (sudoers_cmnd[dlen - 1] == '/')
-       return(command_matches_dir(sudoers_cmnd, dlen));
+       return command_matches_dir(sudoers_cmnd, dlen);
 
     /* Only proceed if user_base and basename(sudoers_cmnd) match */
     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
@@ -537,7 +552,7 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
        base++;
     if (strcmp(user_base, base) != 0 ||
        stat(sudoers_cmnd, &sudoers_stat) == -1)
-       return(FALSE);
+       return FALSE;
 
     /*
      * Return true if inode/device matches AND
@@ -548,16 +563,13 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
     if (user_stat != NULL &&
        (user_stat->st_dev != sudoers_stat.st_dev ||
        user_stat->st_ino != sudoers_stat.st_ino))
-       return(FALSE);
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+       return FALSE;
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        efree(safe_cmnd);
        safe_cmnd = estrdup(sudoers_cmnd);
-       return(TRUE);
+       return TRUE;
     }
-    return(FALSE);
+    return FALSE;
 }
 
 /*
@@ -578,10 +590,12 @@ command_matches_dir(sudoers_dir, dlen)
      */
     dirp = opendir(sudoers_dir);
     if (dirp == NULL)
-       return(FALSE);
+       return FALSE;
 
-    if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf))
-       return(FALSE);
+    if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
+       closedir(dirp);
+       return FALSE;
+    }
     while ((dent = readdir(dirp)) != NULL) {
        /* ignore paths > PATH_MAX (XXX - log) */
        buf[dlen] = '\0';
@@ -592,8 +606,9 @@ command_matches_dir(sudoers_dir, dlen)
        if (strcmp(user_base, dent->d_name) != 0 ||
            stat(buf, &sudoers_stat) == -1)
            continue;
-       if (user_stat->st_dev == sudoers_stat.st_dev &&
-           user_stat->st_ino == sudoers_stat.st_ino) {
+       if (user_stat == NULL ||
+           (user_stat->st_dev == sudoers_stat.st_dev &&
+           user_stat->st_ino == sudoers_stat.st_ino)) {
            efree(safe_cmnd);
            safe_cmnd = estrdup(buf);
            break;
@@ -601,7 +616,7 @@ command_matches_dir(sudoers_dir, dlen)
     }
 
     closedir(dirp);
-    return(dent != NULL);
+    return dent != NULL;
 }
 
 static int
@@ -609,22 +624,21 @@ addr_matches_if(n)
     char *n;
 {
     int i;
-    struct in_addr addr;
+    union sudo_in_addr_un addr;
     struct interface *ifp;
 #ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6;
     int j;
 #endif
     int family;
 
 #ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0) {
+    if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
        family = AF_INET6;
     } else
 #endif
     {
        family = AF_INET;
-       addr.s_addr = inet_addr(n);
+       addr.ip4.s_addr = inet_addr(n);
     }
 
     for (i = 0; i < num_interfaces; i++) {
@@ -633,27 +647,27 @@ addr_matches_if(n)
            continue;
        switch(family) {
            case AF_INET:
-               if (ifp->addr.ip4.s_addr == addr.s_addr ||
+               if (ifp->addr.ip4.s_addr == addr.ip4.s_addr ||
                    (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
-                   == addr.s_addr)
-                   return(TRUE);
+                   == addr.ip4.s_addr)
+                   return TRUE;
                break;
 #ifdef HAVE_IN6_ADDR
            case AF_INET6:
-               if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
-                   sizeof(addr6.s6_addr)) == 0)
-                   return(TRUE);
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
+               if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
+                   sizeof(addr.ip6.s6_addr)) == 0)
+                   return TRUE;
+               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
                        break;
                }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
+               if (j == sizeof(addr.ip6.s6_addr))
+                   return TRUE;
 #endif
        }
     }
 
-    return(FALSE);
+    return FALSE;
 }
 
 static int
@@ -662,46 +676,45 @@ addr_matches_if_netmask(n, m)
     char *m;
 {
     int i;
-    struct in_addr addr, mask;
+    union sudo_in_addr_un addr, mask;
     struct interface *ifp;
 #ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6, mask6;
     int j;
 #endif
     int family;
 
 #ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0)
+    if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
        family = AF_INET6;
     else
 #endif
     {
        family = AF_INET;
-       addr.s_addr = inet_addr(n);
+       addr.ip4.s_addr = inet_addr(n);
     }
 
     if (family == AF_INET) {
        if (strchr(m, '.'))
-           mask.s_addr = inet_addr(m);
+           mask.ip4.s_addr = inet_addr(m);
        else {
            i = 32 - atoi(m);
-           mask.s_addr = 0xffffffff;
-           mask.s_addr >>= i;
-           mask.s_addr <<= i;
-           mask.s_addr = htonl(mask.s_addr);
+           mask.ip4.s_addr = 0xffffffff;
+           mask.ip4.s_addr >>= i;
+           mask.ip4.s_addr <<= i;
+           mask.ip4.s_addr = htonl(mask.ip4.s_addr);
        }
     }
 #ifdef HAVE_IN6_ADDR
     else {
-       if (inet_pton(AF_INET6, m, &mask6) <= 0) {
+       if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
            j = atoi(m);
            for (i = 0; i < 16; i++) {
                if (j < i * 8)
-                   mask6.s6_addr[i] = 0;
+                   mask.ip6.s6_addr[i] = 0;
                else if (i * 8 + 8 <= j)
-                   mask6.s6_addr[i] = 0xff;
+                   mask.ip6.s6_addr[i] = 0xff;
                else
-                   mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
+                   mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
            }
        }
     }
@@ -713,21 +726,21 @@ addr_matches_if_netmask(n, m)
            continue;
        switch(family) {
            case AF_INET:
-               if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
-                   return(TRUE);
+               if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
+                   return TRUE;
 #ifdef HAVE_IN6_ADDR
            case AF_INET6:
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
+               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
                        break;
                }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
+               if (j == sizeof(addr.ip6.s6_addr))
+                   return TRUE;
 #endif /* HAVE_IN6_ADDR */
        }
     }
 
-    return(FALSE);
+    return FALSE;
 }
 
 /*
@@ -749,7 +762,7 @@ addr_matches(n)
     } else
        retval = addr_matches_if(n);
 
-    return(retval);
+    return retval;
 }
 
 /*
@@ -763,14 +776,14 @@ hostname_matches(shost, lhost, pattern)
 {
     if (has_meta(pattern)) {
        if (strchr(pattern, '.'))
-           return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
+           return !fnmatch(pattern, lhost, FNM_CASEFOLD);
        else
-           return(!fnmatch(pattern, shost, FNM_CASEFOLD));
+           return !fnmatch(pattern, shost, FNM_CASEFOLD);
     } else {
        if (strchr(pattern, '.'))
-           return(!strcasecmp(lhost, pattern));
+           return !strcasecmp(lhost, pattern);
        else
-           return(!strcasecmp(shost, pattern));
+           return !strcasecmp(shost, pattern);
     }
 }
 
@@ -787,9 +800,9 @@ userpw_matches(sudoers_user, user, pw)
     if (pw != NULL && *sudoers_user == '#') {
        uid_t uid = (uid_t) atoi(sudoers_user + 1);
        if (uid == pw->pw_uid)
-           return(TRUE);
+           return TRUE;
     }
-    return(strcmp(sudoers_user, user) == 0);
+    return strcmp(sudoers_user, user) == 0;
 }
 
 /*
@@ -804,9 +817,9 @@ group_matches(sudoers_group, gr)
     if (*sudoers_group == '#') {
        gid_t gid = (gid_t) atoi(sudoers_group + 1);
        if (gid == gr->gr_gid)
-           return(TRUE);
+           return TRUE;
     }
-    return(strcmp(gr->gr_name, sudoers_group) == 0);
+    return strcmp(gr->gr_name, sudoers_group) == 0;
 }
 
 /*
@@ -819,54 +832,46 @@ usergr_matches(group, user, pw)
     char *user;
     struct passwd *pw;
 {
-    struct group *grp = NULL;
-    char **cur;
-    int i;
+    int matched = FALSE;
+    struct passwd *pw0 = NULL;
 
     /* make sure we have a valid usergroup, sudo style */
     if (*group++ != '%')
-       return(FALSE);
+       goto done;
 
 #ifdef USING_NONUNIX_GROUPS
-    if (*group == ':')
-       return(sudo_nonunix_groupcheck(++group, user, pw));   
+    if (*group == ':') {
+       matched = sudo_nonunix_groupcheck(++group, user, pw);
+       goto done;
+    }
 #endif /* USING_NONUNIX_GROUPS */
 
     /* look up user's primary gid in the passwd file */
-    if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
-       goto try_supplementary;
-
-    /* check against user's primary (passwd file) gid */
-    if ((grp = sudo_getgrnam(group)) == NULL)
-       goto try_supplementary;
-    if (grp->gr_gid == pw->pw_gid)
-       return(TRUE);
-
-    /*
-     * If we are matching the invoking or list user and that user has a
-     * supplementary group vector, check it first.
-     */
-    if (strcmp(user, 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 (pw == NULL) {
+       if ((pw0 = sudo_getpwnam(user)) == NULL)
+           goto done;
+       pw = pw0;
     }
 
-try_supplementary:
-    if (grp != NULL && grp->gr_mem != NULL) {
-       for (cur = grp->gr_mem; *cur; cur++)
-           if (strcmp(*cur, user) == 0)
-               return(TRUE);
+    if (user_in_group(pw, group)) {
+       matched = TRUE;
+       goto done;
     }
 
 #ifdef USING_NONUNIX_GROUPS
     /* not a Unix group, could be an AD group */
     if (sudo_nonunix_groupcheck_available() &&
-       sudo_nonunix_groupcheck(group, user, pw))
-       return(TRUE);
+       sudo_nonunix_groupcheck(group, user, pw)) {
+       matched = TRUE;
+       goto done;
+    }
 #endif /* USING_NONUNIX_GROUPS */
 
-    return(FALSE);
+done:
+    if (pw0 != NULL)
+       pw_delref(pw0);
+
+    return matched;
 }
 
 /*
@@ -890,7 +895,7 @@ netgr_matches(netgr, lhost, shost, user)
 
     /* make sure we have a valid netgroup, sudo style */
     if (*netgr++ != '+')
-       return(FALSE);
+       return FALSE;
 
 #ifdef HAVE_GETDOMAINNAME
     /* get the domain name (if any) */
@@ -906,10 +911,10 @@ netgr_matches(netgr, lhost, shost, user)
 
 #ifdef HAVE_INNETGR
     if (innetgr(netgr, lhost, user, domain))
-       return(TRUE);
+       return TRUE;
     else if (lhost != shost && innetgr(netgr, shost, user, domain))
-       return(TRUE);
+       return TRUE;
 #endif /* HAVE_INNETGR */
 
-    return(FALSE);
+    return FALSE;
 }