Annotation of embedaddon/sudo/plugins/sudoers/pwutil.c, revision 1.1.1.4

1.1       misho       1: /*
1.1.1.4 ! misho       2:  * Copyright (c) 1996, 1998-2005, 2007-2013
1.1       misho       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"
1.1.1.4 ! misho      54: #include "pwutil.h"
1.1       misho      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: 
1.1.1.2   misho      69: /*
1.1       misho      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
1.1.1.3   misho      92: sudo_pw_addref(struct passwd *pw)
1.1       misho      93: {
1.1.1.3   misho      94:     debug_decl(sudo_pw_addref, SUDO_DEBUG_NSS)
1.1       misho      95:     ptr_to_item(pw)->refcnt++;
1.1.1.2   misho      96:     debug_return;
1.1       misho      97: }
                     98: 
                     99: static void
1.1.1.3   misho     100: sudo_pw_delref_item(void *v)
1.1       misho     101: {
                    102:     struct cache_item *item = v;
1.1.1.3   misho     103:     debug_decl(sudo_pw_delref_item, SUDO_DEBUG_NSS)
1.1       misho     104: 
                    105:     if (--item->refcnt == 0)
                    106:        efree(item);
1.1.1.2   misho     107: 
                    108:     debug_return;
1.1       misho     109: }
                    110: 
                    111: void
1.1.1.3   misho     112: sudo_pw_delref(struct passwd *pw)
1.1       misho     113: {
1.1.1.3   misho     114:     debug_decl(sudo_pw_delref, SUDO_DEBUG_NSS)
                    115:     sudo_pw_delref_item(ptr_to_item(pw));
1.1.1.2   misho     116:     debug_return;
1.1       misho     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;
1.1.1.2   misho     127:     debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS)
1.1       misho     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
1.1.1.4 ! misho     140:     item = sudo_make_pwitem(uid, NULL);
        !           141:     if (item == NULL) {
1.1.1.2   misho     142:        item = ecalloc(1, sizeof(*item));
1.1       misho     143:        item->refcnt = 1;
                    144:        item->k.uid = uid;
1.1.1.2   misho     145:        /* item->d.pw = NULL; */
1.1       misho     146:     }
1.1.1.4 ! misho     147:     if (rbinsert(pwcache_byuid, item) != NULL)
        !           148:        fatalx(_("unable to cache uid %u, already exists"),
        !           149:            (unsigned int) uid);
1.1       misho     150: #ifdef HAVE_SETAUTHDB
                    151:     aix_restoreauthdb();
                    152: #endif
                    153: done:
                    154:     item->refcnt++;
1.1.1.2   misho     155:     debug_return_ptr(item->d.pw);
1.1       misho     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;
1.1.1.2   misho     167:     debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS)
1.1       misho     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
1.1.1.4 ! misho     180:     item = sudo_make_pwitem((uid_t)-1, name);
        !           181:     if (item == NULL) {
1.1       misho     182:        len = strlen(name) + 1;
1.1.1.2   misho     183:        item = ecalloc(1, sizeof(*item) + len);
1.1       misho     184:        item->refcnt = 1;
                    185:        item->k.name = (char *) item + sizeof(*item);
                    186:        memcpy(item->k.name, name, len);
1.1.1.2   misho     187:        /* item->d.pw = NULL; */
1.1       misho     188:     }
1.1.1.4 ! misho     189:     if (rbinsert(pwcache_byname, item) != NULL)
        !           190:        fatalx(_("unable to cache user %s, already exists"), name);
1.1       misho     191: #ifdef HAVE_SETAUTHDB
                    192:     aix_restoreauthdb();
                    193: #endif
                    194: done:
                    195:     item->refcnt++;
1.1.1.2   misho     196:     debug_return_ptr(item->d.pw);
1.1       misho     197: }
                    198: 
                    199: /*
1.1.1.4 ! misho     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.
1.1       misho     202:  */
                    203: struct passwd *
1.1.1.4 ! misho     204: sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
        !           205:     const char *shell)
1.1       misho     206: {
1.1.1.2   misho     207:     struct cache_item_pw *pwitem;
1.1       misho     208:     struct passwd *pw;
                    209:     struct rbnode *node;
1.1.1.4 ! misho     210:     size_t len, name_len, home_len, shell_len;
1.1       misho     211:     int i;
1.1.1.4 ! misho     212:     debug_decl(sudo_mkpwent, SUDO_DEBUG_NSS)
1.1       misho     213: 
1.1.1.4 ! misho     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 */ +
1.1       misho     224:        sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
1.1.1.4 ! misho     225:        home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */;
1.1       misho     226: 
                    227:     for (i = 0; i < 2; i++) {
1.1.1.2   misho     228:        pwitem = ecalloc(1, len);
                    229:        pw = &pwitem->pw;
1.1       misho     230:        pw->pw_uid = uid;
                    231:        pw->pw_gid = gid;
1.1.1.2   misho     232:        pw->pw_name = (char *)(pwitem + 1);
1.1.1.4 ! misho     233:        memcpy(pw->pw_name, user, name_len + 1);
        !           234:        pw->pw_passwd = pw->pw_name + name_len + 1;
1.1       misho     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;
1.1.1.4 ! misho     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);
1.1       misho     242: 
1.1.1.2   misho     243:        pwitem->cache.refcnt = 1;
                    244:        pwitem->cache.d.pw = pw;
1.1       misho     245:        if (i == 0) {
1.1.1.4 ! misho     246:            /* Store by uid if it doesn't already exist. */
1.1.1.2   misho     247:            pwitem->cache.k.uid = pw->pw_uid;
                    248:            if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {
1.1.1.4 ! misho     249:                /* Already exists, free the item we created. */
        !           250:                efree(pwitem);
        !           251:                pwitem = (struct cache_item_pw *) node->data;
1.1       misho     252:            }
                    253:        } else {
1.1.1.4 ! misho     254:            /* Store by name if it doesn't already exist. */
1.1.1.2   misho     255:            pwitem->cache.k.name = pw->pw_name;
                    256:            if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {
1.1.1.4 ! misho     257:                /* Already exists, free the item we created. */
        !           258:                efree(pwitem);
        !           259:                pwitem = (struct cache_item_pw *) node->data;
1.1       misho     260:            }
                    261:        }
                    262:     }
1.1.1.2   misho     263:     pwitem->cache.refcnt++;
1.1.1.4 ! misho     264:     debug_return_ptr(&pwitem->pw);
1.1       misho     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:     uid_t uid;
                    274: 
                    275:     uid = (uid_t) atoi(user + 1);
1.1.1.4 ! misho     276:     return sudo_mkpwent(user, uid, gid, NULL, NULL);
1.1       misho     277: }
                    278: 
                    279: void
                    280: sudo_setpwent(void)
                    281: {
1.1.1.2   misho     282:     debug_decl(sudo_setpwent, SUDO_DEBUG_NSS)
                    283: 
1.1       misho     284:     setpwent();
                    285:     if (pwcache_byuid == NULL)
                    286:        pwcache_byuid = rbcreate(cmp_pwuid);
                    287:     if (pwcache_byname == NULL)
                    288:        pwcache_byname = rbcreate(cmp_pwnam);
1.1.1.2   misho     289: 
                    290:     debug_return;
1.1       misho     291: }
                    292: 
                    293: void
                    294: sudo_freepwcache(void)
                    295: {
1.1.1.2   misho     296:     debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS)
                    297: 
1.1       misho     298:     if (pwcache_byuid != NULL) {
1.1.1.3   misho     299:        rbdestroy(pwcache_byuid, sudo_pw_delref_item);
1.1       misho     300:        pwcache_byuid = NULL;
                    301:     }
                    302:     if (pwcache_byname != NULL) {
1.1.1.3   misho     303:        rbdestroy(pwcache_byname, sudo_pw_delref_item);
1.1       misho     304:        pwcache_byname = NULL;
                    305:     }
1.1.1.2   misho     306: 
                    307:     debug_return;
1.1       misho     308: }
                    309: 
                    310: void
                    311: sudo_endpwent(void)
                    312: {
1.1.1.2   misho     313:     debug_decl(sudo_endpwent, SUDO_DEBUG_NSS)
                    314: 
1.1       misho     315:     endpwent();
                    316:     sudo_freepwcache();
1.1.1.2   misho     317: 
                    318:     debug_return;
1.1       misho     319: }
                    320: 
                    321: /*
                    322:  * Compare by gid.
                    323:  */
                    324: static int
                    325: cmp_grgid(const void *v1, const void *v2)
                    326: {
                    327:     const struct cache_item *ci1 = (const struct cache_item *) v1;
                    328:     const struct cache_item *ci2 = (const struct cache_item *) v2;
                    329:     return ci1->k.gid - ci2->k.gid;
                    330: }
                    331: 
                    332: void
1.1.1.3   misho     333: sudo_gr_addref(struct group *gr)
1.1       misho     334: {
1.1.1.3   misho     335:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
1.1       misho     336:     ptr_to_item(gr)->refcnt++;
1.1.1.2   misho     337:     debug_return;
1.1       misho     338: }
                    339: 
                    340: static void
1.1.1.3   misho     341: sudo_gr_delref_item(void *v)
1.1       misho     342: {
                    343:     struct cache_item *item = v;
1.1.1.3   misho     344:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
1.1       misho     345: 
                    346:     if (--item->refcnt == 0)
                    347:        efree(item);
1.1.1.2   misho     348: 
                    349:     debug_return;
1.1       misho     350: }
                    351: 
                    352: void
1.1.1.3   misho     353: sudo_gr_delref(struct group *gr)
1.1       misho     354: {
1.1.1.3   misho     355:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
                    356:     sudo_gr_delref_item(ptr_to_item(gr));
1.1.1.2   misho     357:     debug_return;
1.1       misho     358: }
                    359: 
                    360: /*
                    361:  * Get a group entry by gid and allocate space for it.
                    362:  */
                    363: struct group *
                    364: sudo_getgrgid(gid_t gid)
                    365: {
                    366:     struct cache_item key, *item;
                    367:     struct rbnode *node;
1.1.1.2   misho     368:     debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS)
1.1       misho     369: 
                    370:     key.k.gid = gid;
                    371:     if ((node = rbfind(grcache_bygid, &key)) != NULL) {
                    372:        item = (struct cache_item *) node->data;
                    373:        goto done;
                    374:     }
                    375:     /*
                    376:      * Cache group db entry if it exists or a negative response if not.
                    377:      */
1.1.1.4 ! misho     378:     item = sudo_make_gritem(gid, NULL);
        !           379:     if (item == NULL) {
1.1.1.2   misho     380:        item = ecalloc(1, sizeof(*item));
1.1       misho     381:        item->refcnt = 1;
                    382:        item->k.gid = gid;
1.1.1.2   misho     383:        /* item->d.gr = NULL; */
1.1       misho     384:     }
1.1.1.4 ! misho     385:     if (rbinsert(grcache_bygid, item) != NULL)
        !           386:        fatalx(_("unable to cache gid %u, already exists"),
        !           387:            (unsigned int) gid);
1.1       misho     388: done:
                    389:     item->refcnt++;
1.1.1.2   misho     390:     debug_return_ptr(item->d.gr);
1.1       misho     391: }
                    392: 
                    393: /*
                    394:  * Get a group entry by name and allocate space for it.
                    395:  */
                    396: struct group *
                    397: sudo_getgrnam(const char *name)
                    398: {
                    399:     struct cache_item key, *item;
                    400:     struct rbnode *node;
                    401:     size_t len;
1.1.1.2   misho     402:     debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS)
1.1       misho     403: 
                    404:     key.k.name = (char *) name;
                    405:     if ((node = rbfind(grcache_byname, &key)) != NULL) {
                    406:        item = (struct cache_item *) node->data;
                    407:        goto done;
                    408:     }
                    409:     /*
                    410:      * Cache group db entry if it exists or a negative response if not.
                    411:      */
1.1.1.4 ! misho     412:     item = sudo_make_gritem((gid_t)-1, name);
        !           413:     if (item == NULL) {
1.1       misho     414:        len = strlen(name) + 1;
1.1.1.2   misho     415:        item = ecalloc(1, sizeof(*item) + len);
1.1       misho     416:        item->refcnt = 1;
                    417:        item->k.name = (char *) item + sizeof(*item);
                    418:        memcpy(item->k.name, name, len);
1.1.1.2   misho     419:        /* item->d.gr = NULL; */
1.1       misho     420:     }
1.1.1.4 ! misho     421:     if (rbinsert(grcache_byname, item) != NULL)
        !           422:        fatalx(_("unable to cache group %s, already exists"), name);
1.1       misho     423: done:
                    424:     item->refcnt++;
1.1.1.2   misho     425:     debug_return_ptr(item->d.gr);
1.1       misho     426: }
                    427: 
                    428: /*
                    429:  * Take a gid in string form "#123" and return a faked up group struct.
                    430:  */
                    431: struct group *
                    432: sudo_fakegrnam(const char *group)
                    433: {
1.1.1.2   misho     434:     struct cache_item_gr *gritem;
1.1       misho     435:     struct group *gr;
                    436:     struct rbnode *node;
1.1.1.4 ! misho     437:     size_t len, name_len;
1.1       misho     438:     int i;
1.1.1.2   misho     439:     debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
1.1       misho     440: 
1.1.1.4 ! misho     441:     name_len = strlen(group);
        !           442:     len = sizeof(*gritem) + name_len + 1;
1.1       misho     443: 
                    444:     for (i = 0; i < 2; i++) {
1.1.1.2   misho     445:        gritem = ecalloc(1, len);
                    446:        gr = &gritem->gr;
1.1       misho     447:        gr->gr_gid = (gid_t) atoi(group + 1);
1.1.1.2   misho     448:        gr->gr_name = (char *)(gritem + 1);
1.1.1.4 ! misho     449:        memcpy(gr->gr_name, group, name_len + 1);
1.1       misho     450: 
1.1.1.2   misho     451:        gritem->cache.refcnt = 1;
                    452:        gritem->cache.d.gr = gr;
1.1       misho     453:        if (i == 0) {
1.1.1.4 ! misho     454:            /* Store by gid if it doesn't already exist. */
1.1.1.2   misho     455:            gritem->cache.k.gid = gr->gr_gid;
                    456:            if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
1.1.1.4 ! misho     457:                /* Already exists, free the item we created. */
        !           458:                efree(gritem);
        !           459:                gritem = (struct cache_item_gr *) node->data;
1.1       misho     460:            }
                    461:        } else {
                    462:            /* Store by name, overwriting cached version. */
1.1.1.2   misho     463:            gritem->cache.k.name = gr->gr_name;
                    464:            if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
1.1.1.4 ! misho     465:                /* Already exists, free the item we created. */
        !           466:                efree(gritem);
        !           467:                gritem = (struct cache_item_gr *) node->data;
1.1       misho     468:            }
                    469:        }
                    470:     }
1.1.1.2   misho     471:     gritem->cache.refcnt++;
1.1.1.4 ! misho     472:     debug_return_ptr(&gritem->gr);
1.1       misho     473: }
                    474: 
                    475: void
1.1.1.3   misho     476: sudo_grlist_addref(struct group_list *grlist)
1.1       misho     477: {
1.1.1.3   misho     478:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
1.1       misho     479:     ptr_to_item(grlist)->refcnt++;
1.1.1.2   misho     480:     debug_return;
1.1       misho     481: }
                    482: 
                    483: static void
1.1.1.3   misho     484: sudo_grlist_delref_item(void *v)
1.1       misho     485: {
                    486:     struct cache_item *item = v;
1.1.1.3   misho     487:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
1.1       misho     488: 
                    489:     if (--item->refcnt == 0)
                    490:        efree(item);
1.1.1.2   misho     491: 
                    492:     debug_return;
1.1       misho     493: }
                    494: 
                    495: void
1.1.1.3   misho     496: sudo_grlist_delref(struct group_list *grlist)
1.1       misho     497: {
1.1.1.3   misho     498:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
                    499:     sudo_grlist_delref_item(ptr_to_item(grlist));
1.1.1.2   misho     500:     debug_return;
1.1       misho     501: }
                    502: 
                    503: void
                    504: sudo_setgrent(void)
                    505: {
1.1.1.2   misho     506:     debug_decl(sudo_setgrent, SUDO_DEBUG_NSS)
                    507: 
1.1       misho     508:     setgrent();
                    509:     if (grcache_bygid == NULL)
                    510:        grcache_bygid = rbcreate(cmp_grgid);
                    511:     if (grcache_byname == NULL)
                    512:        grcache_byname = rbcreate(cmp_grnam);
                    513:     if (grlist_cache == NULL)
                    514:        grlist_cache = rbcreate(cmp_grnam);
1.1.1.2   misho     515: 
                    516:     debug_return;
1.1       misho     517: }
                    518: 
                    519: void
                    520: sudo_freegrcache(void)
                    521: {
1.1.1.2   misho     522:     debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS)
                    523: 
1.1       misho     524:     if (grcache_bygid != NULL) {
1.1.1.3   misho     525:        rbdestroy(grcache_bygid, sudo_gr_delref_item);
1.1       misho     526:        grcache_bygid = NULL;
                    527:     }
                    528:     if (grcache_byname != NULL) {
1.1.1.3   misho     529:        rbdestroy(grcache_byname, sudo_gr_delref_item);
1.1       misho     530:        grcache_byname = NULL;
                    531:     }
                    532:     if (grlist_cache != NULL) {
1.1.1.3   misho     533:        rbdestroy(grlist_cache, sudo_grlist_delref_item);
1.1       misho     534:        grlist_cache = NULL;
                    535:     }
1.1.1.2   misho     536: 
                    537:     debug_return;
1.1       misho     538: }
                    539: 
                    540: void
                    541: sudo_endgrent(void)
                    542: {
1.1.1.2   misho     543:     debug_decl(sudo_endgrent, SUDO_DEBUG_NSS)
                    544: 
1.1       misho     545:     endgrent();
                    546:     sudo_freegrcache();
1.1.1.2   misho     547: 
                    548:     debug_return;
1.1       misho     549: }
                    550: 
                    551: struct group_list *
1.1.1.3   misho     552: sudo_get_grlist(struct passwd *pw)
1.1       misho     553: {
                    554:     struct cache_item key, *item;
                    555:     struct rbnode *node;
                    556:     size_t len;
1.1.1.3   misho     557:     debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)
1.1       misho     558: 
                    559:     key.k.name = pw->pw_name;
                    560:     if ((node = rbfind(grlist_cache, &key)) != NULL) {
                    561:        item = (struct cache_item *) node->data;
                    562:        goto done;
                    563:     }
                    564:     /*
                    565:      * Cache group db entry if it exists or a negative response if not.
                    566:      */
1.1.1.4 ! misho     567:     item = sudo_make_grlist_item(pw, NULL, NULL);
        !           568:     if (item == NULL) {
1.1       misho     569:        /* Should not happen. */
                    570:        len = strlen(pw->pw_name) + 1;
1.1.1.2   misho     571:        item = ecalloc(1, sizeof(*item) + len);
1.1       misho     572:        item->refcnt = 1;
                    573:        item->k.name = (char *) item + sizeof(*item);
                    574:        memcpy(item->k.name, pw->pw_name, len);
1.1.1.2   misho     575:        /* item->d.grlist = NULL; */
1.1       misho     576:     }
1.1.1.4 ! misho     577:     if (rbinsert(grlist_cache, item) != NULL)
        !           578:        fatalx(_("unable to cache group list for %s, already exists"),
        !           579:            pw->pw_name);
1.1       misho     580: done:
                    581:     item->refcnt++;
1.1.1.2   misho     582:     debug_return_ptr(item->d.grlist);
1.1       misho     583: }
                    584: 
1.1.1.4 ! misho     585: void
        !           586: sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids)
        !           587: {
        !           588:     struct cache_item key, *item;
        !           589:     struct rbnode *node;
        !           590:     debug_decl(sudo_set_grlist, SUDO_DEBUG_NSS)
        !           591: 
        !           592:     /*
        !           593:      * Cache group db entry if it doesn't already exist
        !           594:      */
        !           595:     key.k.name = pw->pw_name;
        !           596:     if ((node = rbfind(grlist_cache, &key)) == NULL) {
        !           597:        if ((item = sudo_make_grlist_item(pw, groups, gids)) == NULL)
        !           598:            fatalx(_("unable to parse groups for %s"), pw->pw_name);
        !           599:        if (rbinsert(grlist_cache, item) != NULL)
        !           600:            fatalx(_("unable to cache group list for %s, already exists"),
        !           601:                pw->pw_name);
        !           602:     }
        !           603:     debug_return;
        !           604: }
        !           605: 
1.1.1.2   misho     606: bool
1.1       misho     607: user_in_group(struct passwd *pw, const char *group)
                    608: {
                    609:     struct group_list *grlist;
                    610:     struct group *grp = NULL;
1.1.1.2   misho     611:     int i;
                    612:     bool matched = false;
                    613:     debug_decl(user_in_group, SUDO_DEBUG_NSS)
1.1       misho     614: 
1.1.1.3   misho     615:     if ((grlist = sudo_get_grlist(pw)) != NULL) {
1.1       misho     616:        /*
                    617:         * If it could be a sudo-style group ID check gids first.
                    618:         */
                    619:        if (group[0] == '#') {
                    620:            gid_t gid = atoi(group + 1);
                    621:            if (gid == pw->pw_gid) {
1.1.1.2   misho     622:                matched = true;
1.1       misho     623:                goto done;
                    624:            }
                    625:            for (i = 0; i < grlist->ngids; i++) {
                    626:                if (gid == grlist->gids[i]) {
1.1.1.2   misho     627:                    matched = true;
1.1       misho     628:                    goto done;
                    629:                }
                    630:            }
                    631:        }
                    632: 
                    633:        /*
                    634:         * Next check the supplementary group vector.
                    635:         * It usually includes the password db group too.
                    636:         */
                    637:        for (i = 0; i < grlist->ngroups; i++) {
                    638:            if (strcasecmp(group, grlist->groups[i]) == 0) {
1.1.1.2   misho     639:                matched = true;
1.1       misho     640:                goto done;
                    641:            }
                    642:        }
                    643: 
                    644:        /* Finally check against user's primary (passwd file) group. */
                    645:        if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
                    646:            if (strcasecmp(group, grp->gr_name) == 0) {
1.1.1.2   misho     647:                matched = true;
1.1       misho     648:                goto done;
                    649:            }
                    650:        }
                    651: done:
                    652:        if (grp != NULL)
1.1.1.3   misho     653:            sudo_gr_delref(grp);
                    654:        sudo_grlist_delref(grlist);
1.1       misho     655:     }
1.1.1.2   misho     656:     debug_return_bool(matched);
1.1       misho     657: }

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