File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / pwutil.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 1 month ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 1996, 1998-2005, 2007-2013
    3:  *	Todd C. Miller <Todd.Miller@courtesan.com>
    4:  *
    5:  * Permission to use, copy, modify, and distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  *
   17:  * Sponsored in part by the Defense Advanced Research Projects
   18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   20:  */
   21: 
   22: #include <config.h>
   23: 
   24: #include <sys/types.h>
   25: #include <stdio.h>
   26: #ifdef STDC_HEADERS
   27: # include <stdlib.h>
   28: # include <stddef.h>
   29: #else
   30: # ifdef HAVE_STDLIB_H
   31: #  include <stdlib.h>
   32: # endif
   33: #endif /* STDC_HEADERS */
   34: #ifdef HAVE_STRING_H
   35: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
   36: #  include <memory.h>
   37: # endif
   38: # include <string.h>
   39: #endif /* HAVE_STRING_H */
   40: #ifdef HAVE_STRINGS_H
   41: # include <strings.h>
   42: #endif /* HAVE_STRINGS_H */
   43: #ifdef HAVE_UNISTD_H
   44: # include <unistd.h>
   45: #endif /* HAVE_UNISTD_H */
   46: #ifdef HAVE_SETAUTHDB
   47: # include <usersec.h>
   48: #endif /* HAVE_SETAUTHDB */
   49: #include <pwd.h>
   50: #include <grp.h>
   51: 
   52: #include "sudoers.h"
   53: #include "redblack.h"
   54: #include "pwutil.h"
   55: 
   56: /*
   57:  * The passwd and group caches.
   58:  */
   59: static struct rbtree *pwcache_byuid, *pwcache_byname;
   60: static struct rbtree *grcache_bygid, *grcache_byname;
   61: static struct rbtree *grlist_cache;
   62: 
   63: static int  cmp_pwuid(const void *, const void *);
   64: static int  cmp_pwnam(const void *, const void *);
   65: static int  cmp_grgid(const void *, const void *);
   66: 
   67: #define cmp_grnam	cmp_pwnam
   68: 
   69: /*
   70:  * Compare by uid.
   71:  */
   72: static int
   73: cmp_pwuid(const void *v1, const void *v2)
   74: {
   75:     const struct cache_item *ci1 = (const struct cache_item *) v1;
   76:     const struct cache_item *ci2 = (const struct cache_item *) v2;
   77:     return ci1->k.uid - ci2->k.uid;
   78: }
   79: 
   80: /*
   81:  * Compare by user name.
   82:  */
   83: static int
   84: cmp_pwnam(const void *v1, const void *v2)
   85: {
   86:     const struct cache_item *ci1 = (const struct cache_item *) v1;
   87:     const struct cache_item *ci2 = (const struct cache_item *) v2;
   88:     return strcmp(ci1->k.name, ci2->k.name);
   89: }
   90: 
   91: void
   92: sudo_pw_addref(struct passwd *pw)
   93: {
   94:     debug_decl(sudo_pw_addref, SUDO_DEBUG_NSS)
   95:     ptr_to_item(pw)->refcnt++;
   96:     debug_return;
   97: }
   98: 
   99: static void
  100: sudo_pw_delref_item(void *v)
  101: {
  102:     struct cache_item *item = v;
  103:     debug_decl(sudo_pw_delref_item, SUDO_DEBUG_NSS)
  104: 
  105:     if (--item->refcnt == 0)
  106: 	efree(item);
  107: 
  108:     debug_return;
  109: }
  110: 
  111: void
  112: sudo_pw_delref(struct passwd *pw)
  113: {
  114:     debug_decl(sudo_pw_delref, SUDO_DEBUG_NSS)
  115:     sudo_pw_delref_item(ptr_to_item(pw));
  116:     debug_return;
  117: }
  118: 
  119: /*
  120:  * Get a password entry by uid and allocate space for it.
  121:  */
  122: struct passwd *
  123: sudo_getpwuid(uid_t uid)
  124: {
  125:     struct cache_item key, *item;
  126:     struct rbnode *node;
  127:     debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS)
  128: 
  129:     key.k.uid = uid;
  130:     if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
  131: 	item = (struct cache_item *) node->data;
  132: 	goto done;
  133:     }
  134:     /*
  135:      * Cache passwd db entry if it exists or a negative response if not.
  136:      */
  137: #ifdef HAVE_SETAUTHDB
  138:     aix_setauthdb(IDtouser(uid));
  139: #endif
  140:     item = sudo_make_pwitem(uid, NULL);
  141:     if (item == NULL) {
  142: 	item = ecalloc(1, sizeof(*item));
  143: 	item->refcnt = 1;
  144: 	item->k.uid = uid;
  145: 	/* item->d.pw = NULL; */
  146:     }
  147:     if (rbinsert(pwcache_byuid, item) != NULL)
  148: 	fatalx(U_("unable to cache uid %u, already exists"),
  149: 	    (unsigned int) uid);
  150: #ifdef HAVE_SETAUTHDB
  151:     aix_restoreauthdb();
  152: #endif
  153: done:
  154:     item->refcnt++;
  155:     debug_return_ptr(item->d.pw);
  156: }
  157: 
  158: /*
  159:  * Get a password entry by name and allocate space for it.
  160:  */
  161: struct passwd *
  162: sudo_getpwnam(const char *name)
  163: {
  164:     struct cache_item key, *item;
  165:     struct rbnode *node;
  166:     size_t len;
  167:     debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS)
  168: 
  169:     key.k.name = (char *) name;
  170:     if ((node = rbfind(pwcache_byname, &key)) != NULL) {
  171: 	item = (struct cache_item *) node->data;
  172: 	goto done;
  173:     }
  174:     /*
  175:      * Cache passwd db entry if it exists or a negative response if not.
  176:      */
  177: #ifdef HAVE_SETAUTHDB
  178:     aix_setauthdb((char *) name);
  179: #endif
  180:     item = sudo_make_pwitem((uid_t)-1, name);
  181:     if (item == NULL) {
  182: 	len = strlen(name) + 1;
  183: 	item = ecalloc(1, sizeof(*item) + len);
  184: 	item->refcnt = 1;
  185: 	item->k.name = (char *) item + sizeof(*item);
  186: 	memcpy(item->k.name, name, len);
  187: 	/* item->d.pw = NULL; */
  188:     }
  189:     if (rbinsert(pwcache_byname, item) != NULL)
  190: 	fatalx(U_("unable to cache user %s, already exists"), name);
  191: #ifdef HAVE_SETAUTHDB
  192:     aix_restoreauthdb();
  193: #endif
  194: done:
  195:     item->refcnt++;
  196:     debug_return_ptr(item->d.pw);
  197: }
  198: 
  199: /*
  200:  * Take a user, uid, gid, home and shell and return a faked up passwd struct.
  201:  * If home or shell are NULL default values will be used.
  202:  */
  203: struct passwd *
  204: sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
  205:     const char *shell)
  206: {
  207:     struct cache_item_pw *pwitem;
  208:     struct passwd *pw;
  209:     struct rbnode *node;
  210:     size_t len, name_len, home_len, shell_len;
  211:     int i;
  212:     debug_decl(sudo_mkpwent, SUDO_DEBUG_NSS)
  213: 
  214:     /* Optional arguments. */
  215:     if (home == NULL)
  216: 	home = "/";
  217:     if (shell == NULL)
  218: 	shell = _PATH_BSHELL;
  219: 
  220:     name_len = strlen(user);
  221:     home_len = strlen(home);
  222:     shell_len = strlen(shell);
  223:     len = sizeof(*pwitem) + name_len + 1 /* pw_name */ +
  224: 	sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
  225: 	home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */;
  226: 
  227:     for (i = 0; i < 2; i++) {
  228: 	pwitem = ecalloc(1, len);
  229: 	pw = &pwitem->pw;
  230: 	pw->pw_uid = uid;
  231: 	pw->pw_gid = gid;
  232: 	pw->pw_name = (char *)(pwitem + 1);
  233: 	memcpy(pw->pw_name, user, name_len + 1);
  234: 	pw->pw_passwd = pw->pw_name + name_len + 1;
  235: 	memcpy(pw->pw_passwd, "*", 2);
  236: 	pw->pw_gecos = pw->pw_passwd + 2;
  237: 	pw->pw_gecos[0] = '\0';
  238: 	pw->pw_dir = pw->pw_gecos + 1;
  239: 	memcpy(pw->pw_dir, home, home_len + 1);
  240: 	pw->pw_shell = pw->pw_dir + home_len + 1;
  241: 	memcpy(pw->pw_shell, shell, shell_len + 1);
  242: 
  243: 	pwitem->cache.refcnt = 1;
  244: 	pwitem->cache.d.pw = pw;
  245: 	if (i == 0) {
  246: 	    /* Store by uid if it doesn't already exist. */
  247: 	    pwitem->cache.k.uid = pw->pw_uid;
  248: 	    if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {
  249: 		/* Already exists, free the item we created. */
  250: 		efree(pwitem);
  251: 		pwitem = (struct cache_item_pw *) node->data;
  252: 	    }
  253: 	} else {
  254: 	    /* Store by name if it doesn't already exist. */
  255: 	    pwitem->cache.k.name = pw->pw_name;
  256: 	    if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {
  257: 		/* Already exists, free the item we created. */
  258: 		efree(pwitem);
  259: 		pwitem = (struct cache_item_pw *) node->data;
  260: 	    }
  261: 	}
  262:     }
  263:     pwitem->cache.refcnt++;
  264:     debug_return_ptr(&pwitem->pw);
  265: }
  266: 
  267: /*
  268:  * Take a uid in string form "#123" and return a faked up passwd struct.
  269:  */
  270: struct passwd *
  271: sudo_fakepwnam(const char *user, gid_t gid)
  272: {
  273:     const char *errstr;
  274:     uid_t uid;
  275:     debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)
  276: 
  277:     uid = (uid_t) atoid(user + 1, NULL, NULL, &errstr);
  278:     if (errstr != NULL) {
  279: 	sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG,
  280: 	    "uid %s %s", user, errstr);
  281: 	debug_return_ptr(NULL);
  282:     }
  283:     debug_return_ptr(sudo_mkpwent(user, uid, gid, NULL, NULL));
  284: }
  285: 
  286: void
  287: sudo_setpwent(void)
  288: {
  289:     debug_decl(sudo_setpwent, SUDO_DEBUG_NSS)
  290: 
  291:     setpwent();
  292:     if (pwcache_byuid == NULL)
  293: 	pwcache_byuid = rbcreate(cmp_pwuid);
  294:     if (pwcache_byname == NULL)
  295: 	pwcache_byname = rbcreate(cmp_pwnam);
  296: 
  297:     debug_return;
  298: }
  299: 
  300: void
  301: sudo_freepwcache(void)
  302: {
  303:     debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS)
  304: 
  305:     if (pwcache_byuid != NULL) {
  306: 	rbdestroy(pwcache_byuid, sudo_pw_delref_item);
  307: 	pwcache_byuid = NULL;
  308:     }
  309:     if (pwcache_byname != NULL) {
  310: 	rbdestroy(pwcache_byname, sudo_pw_delref_item);
  311: 	pwcache_byname = NULL;
  312:     }
  313: 
  314:     debug_return;
  315: }
  316: 
  317: void
  318: sudo_endpwent(void)
  319: {
  320:     debug_decl(sudo_endpwent, SUDO_DEBUG_NSS)
  321: 
  322:     endpwent();
  323:     sudo_freepwcache();
  324: 
  325:     debug_return;
  326: }
  327: 
  328: /*
  329:  * Compare by gid.
  330:  */
  331: static int
  332: cmp_grgid(const void *v1, const void *v2)
  333: {
  334:     const struct cache_item *ci1 = (const struct cache_item *) v1;
  335:     const struct cache_item *ci2 = (const struct cache_item *) v2;
  336:     return ci1->k.gid - ci2->k.gid;
  337: }
  338: 
  339: void
  340: sudo_gr_addref(struct group *gr)
  341: {
  342:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
  343:     ptr_to_item(gr)->refcnt++;
  344:     debug_return;
  345: }
  346: 
  347: static void
  348: sudo_gr_delref_item(void *v)
  349: {
  350:     struct cache_item *item = v;
  351:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
  352: 
  353:     if (--item->refcnt == 0)
  354: 	efree(item);
  355: 
  356:     debug_return;
  357: }
  358: 
  359: void
  360: sudo_gr_delref(struct group *gr)
  361: {
  362:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
  363:     sudo_gr_delref_item(ptr_to_item(gr));
  364:     debug_return;
  365: }
  366: 
  367: /*
  368:  * Get a group entry by gid and allocate space for it.
  369:  */
  370: struct group *
  371: sudo_getgrgid(gid_t gid)
  372: {
  373:     struct cache_item key, *item;
  374:     struct rbnode *node;
  375:     debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS)
  376: 
  377:     key.k.gid = gid;
  378:     if ((node = rbfind(grcache_bygid, &key)) != NULL) {
  379: 	item = (struct cache_item *) node->data;
  380: 	goto done;
  381:     }
  382:     /*
  383:      * Cache group db entry if it exists or a negative response if not.
  384:      */
  385:     item = sudo_make_gritem(gid, NULL);
  386:     if (item == NULL) {
  387: 	item = ecalloc(1, sizeof(*item));
  388: 	item->refcnt = 1;
  389: 	item->k.gid = gid;
  390: 	/* item->d.gr = NULL; */
  391:     }
  392:     if (rbinsert(grcache_bygid, item) != NULL)
  393: 	fatalx(U_("unable to cache gid %u, already exists"),
  394: 	    (unsigned int) gid);
  395: done:
  396:     item->refcnt++;
  397:     debug_return_ptr(item->d.gr);
  398: }
  399: 
  400: /*
  401:  * Get a group entry by name and allocate space for it.
  402:  */
  403: struct group *
  404: sudo_getgrnam(const char *name)
  405: {
  406:     struct cache_item key, *item;
  407:     struct rbnode *node;
  408:     size_t len;
  409:     debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS)
  410: 
  411:     key.k.name = (char *) name;
  412:     if ((node = rbfind(grcache_byname, &key)) != NULL) {
  413: 	item = (struct cache_item *) node->data;
  414: 	goto done;
  415:     }
  416:     /*
  417:      * Cache group db entry if it exists or a negative response if not.
  418:      */
  419:     item = sudo_make_gritem((gid_t)-1, name);
  420:     if (item == NULL) {
  421: 	len = strlen(name) + 1;
  422: 	item = ecalloc(1, sizeof(*item) + len);
  423: 	item->refcnt = 1;
  424: 	item->k.name = (char *) item + sizeof(*item);
  425: 	memcpy(item->k.name, name, len);
  426: 	/* item->d.gr = NULL; */
  427:     }
  428:     if (rbinsert(grcache_byname, item) != NULL)
  429: 	fatalx(U_("unable to cache group %s, already exists"), name);
  430: done:
  431:     item->refcnt++;
  432:     debug_return_ptr(item->d.gr);
  433: }
  434: 
  435: /*
  436:  * Take a gid in string form "#123" and return a faked up group struct.
  437:  */
  438: struct group *
  439: sudo_fakegrnam(const char *group)
  440: {
  441:     struct cache_item_gr *gritem;
  442:     const char *errstr;
  443:     struct group *gr;
  444:     struct rbnode *node;
  445:     size_t len, name_len;
  446:     int i;
  447:     debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
  448: 
  449:     name_len = strlen(group);
  450:     len = sizeof(*gritem) + name_len + 1;
  451: 
  452:     for (i = 0; i < 2; i++) {
  453: 	gritem = ecalloc(1, len);
  454: 	gr = &gritem->gr;
  455: 	gr->gr_gid = (gid_t) atoid(group + 1, NULL, NULL, &errstr);
  456: 	gr->gr_name = (char *)(gritem + 1);
  457: 	memcpy(gr->gr_name, group, name_len + 1);
  458: 	if (errstr != NULL) {
  459: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG,
  460: 		"gid %s %s", group, errstr);
  461: 	    efree(gritem);
  462: 	    debug_return_ptr(NULL);
  463: 	}
  464: 
  465: 	gritem->cache.refcnt = 1;
  466: 	gritem->cache.d.gr = gr;
  467: 	if (i == 0) {
  468: 	    /* Store by gid if it doesn't already exist. */
  469: 	    gritem->cache.k.gid = gr->gr_gid;
  470: 	    if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
  471: 		/* Already exists, free the item we created. */
  472: 		efree(gritem);
  473: 		gritem = (struct cache_item_gr *) node->data;
  474: 	    }
  475: 	} else {
  476: 	    /* Store by name, overwriting cached version. */
  477: 	    gritem->cache.k.name = gr->gr_name;
  478: 	    if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
  479: 		/* Already exists, free the item we created. */
  480: 		efree(gritem);
  481: 		gritem = (struct cache_item_gr *) node->data;
  482: 	    }
  483: 	}
  484:     }
  485:     gritem->cache.refcnt++;
  486:     debug_return_ptr(&gritem->gr);
  487: }
  488: 
  489: void
  490: sudo_grlist_addref(struct group_list *grlist)
  491: {
  492:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
  493:     ptr_to_item(grlist)->refcnt++;
  494:     debug_return;
  495: }
  496: 
  497: static void
  498: sudo_grlist_delref_item(void *v)
  499: {
  500:     struct cache_item *item = v;
  501:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
  502: 
  503:     if (--item->refcnt == 0)
  504: 	efree(item);
  505: 
  506:     debug_return;
  507: }
  508: 
  509: void
  510: sudo_grlist_delref(struct group_list *grlist)
  511: {
  512:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
  513:     sudo_grlist_delref_item(ptr_to_item(grlist));
  514:     debug_return;
  515: }
  516: 
  517: void
  518: sudo_setgrent(void)
  519: {
  520:     debug_decl(sudo_setgrent, SUDO_DEBUG_NSS)
  521: 
  522:     setgrent();
  523:     if (grcache_bygid == NULL)
  524: 	grcache_bygid = rbcreate(cmp_grgid);
  525:     if (grcache_byname == NULL)
  526: 	grcache_byname = rbcreate(cmp_grnam);
  527:     if (grlist_cache == NULL)
  528: 	grlist_cache = rbcreate(cmp_grnam);
  529: 
  530:     debug_return;
  531: }
  532: 
  533: void
  534: sudo_freegrcache(void)
  535: {
  536:     debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS)
  537: 
  538:     if (grcache_bygid != NULL) {
  539: 	rbdestroy(grcache_bygid, sudo_gr_delref_item);
  540: 	grcache_bygid = NULL;
  541:     }
  542:     if (grcache_byname != NULL) {
  543: 	rbdestroy(grcache_byname, sudo_gr_delref_item);
  544: 	grcache_byname = NULL;
  545:     }
  546:     if (grlist_cache != NULL) {
  547: 	rbdestroy(grlist_cache, sudo_grlist_delref_item);
  548: 	grlist_cache = NULL;
  549:     }
  550: 
  551:     debug_return;
  552: }
  553: 
  554: void
  555: sudo_endgrent(void)
  556: {
  557:     debug_decl(sudo_endgrent, SUDO_DEBUG_NSS)
  558: 
  559:     endgrent();
  560:     sudo_freegrcache();
  561: 
  562:     debug_return;
  563: }
  564: 
  565: struct group_list *
  566: sudo_get_grlist(const struct passwd *pw)
  567: {
  568:     struct cache_item key, *item;
  569:     struct rbnode *node;
  570:     size_t len;
  571:     debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)
  572: 
  573:     key.k.name = pw->pw_name;
  574:     if ((node = rbfind(grlist_cache, &key)) != NULL) {
  575: 	item = (struct cache_item *) node->data;
  576: 	goto done;
  577:     }
  578:     /*
  579:      * Cache group db entry if it exists or a negative response if not.
  580:      */
  581:     item = sudo_make_grlist_item(pw, NULL, NULL);
  582:     if (item == NULL) {
  583: 	/* Should not happen. */
  584: 	len = strlen(pw->pw_name) + 1;
  585: 	item = ecalloc(1, sizeof(*item) + len);
  586: 	item->refcnt = 1;
  587: 	item->k.name = (char *) item + sizeof(*item);
  588: 	memcpy(item->k.name, pw->pw_name, len);
  589: 	/* item->d.grlist = NULL; */
  590:     }
  591:     if (rbinsert(grlist_cache, item) != NULL)
  592: 	fatalx(U_("unable to cache group list for %s, already exists"),
  593: 	    pw->pw_name);
  594: done:
  595:     item->refcnt++;
  596:     debug_return_ptr(item->d.grlist);
  597: }
  598: 
  599: void
  600: sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids)
  601: {
  602:     struct cache_item key, *item;
  603:     struct rbnode *node;
  604:     debug_decl(sudo_set_grlist, SUDO_DEBUG_NSS)
  605: 
  606:     /*
  607:      * Cache group db entry if it doesn't already exist
  608:      */
  609:     key.k.name = pw->pw_name;
  610:     if ((node = rbfind(grlist_cache, &key)) == NULL) {
  611: 	if ((item = sudo_make_grlist_item(pw, groups, gids)) == NULL)
  612: 	    fatalx(U_("unable to parse groups for %s"), pw->pw_name);
  613: 	if (rbinsert(grlist_cache, item) != NULL)
  614: 	    fatalx(U_("unable to cache group list for %s, already exists"),
  615: 		pw->pw_name);
  616:     }
  617:     debug_return;
  618: }
  619: 
  620: bool
  621: user_in_group(const struct passwd *pw, const char *group)
  622: {
  623:     struct group_list *grlist;
  624:     struct group *grp = NULL;
  625:     const char *errstr;
  626:     int i;
  627:     bool matched = false;
  628:     debug_decl(user_in_group, SUDO_DEBUG_NSS)
  629: 
  630:     if ((grlist = sudo_get_grlist(pw)) != NULL) {
  631: 	/*
  632: 	 * If it could be a sudo-style group ID check gids first.
  633: 	 */
  634: 	if (group[0] == '#') {
  635: 	    gid_t gid = (gid_t) atoid(group + 1, NULL, NULL, &errstr);
  636: 	    if (errstr != NULL) {
  637: 		sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG,
  638: 		    "gid %s %s", group, errstr);
  639: 	    } else {
  640: 		if (gid == pw->pw_gid) {
  641: 		    matched = true;
  642: 		    goto done;
  643: 		}
  644: 		for (i = 0; i < grlist->ngids; i++) {
  645: 		    if (gid == grlist->gids[i]) {
  646: 			matched = true;
  647: 			goto done;
  648: 		    }
  649: 		}
  650: 	    }
  651: 	}
  652: 
  653: 	/*
  654: 	 * Next check the supplementary group vector.
  655: 	 * It usually includes the password db group too.
  656: 	 */
  657: 	for (i = 0; i < grlist->ngroups; i++) {
  658: 	    if (strcasecmp(group, grlist->groups[i]) == 0) {
  659: 		matched = true;
  660: 		goto done;
  661: 	    }
  662: 	}
  663: 
  664: 	/* Finally check against user's primary (passwd file) group. */
  665: 	if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
  666: 	    if (strcasecmp(group, grp->gr_name) == 0) {
  667: 		matched = true;
  668: 		goto done;
  669: 	    }
  670: 	}
  671: done:
  672: 	if (grp != NULL)
  673: 	    sudo_gr_delref(grp);
  674: 	sudo_grlist_delref(grlist);
  675:     }
  676:     debug_return_bool(matched);
  677: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>