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

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)
1.1.1.5 ! misho     148:        fatalx(U_("unable to cache uid %u, already exists"),
1.1.1.4   misho     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)
1.1.1.5 ! misho     190:        fatalx(U_("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: {
1.1.1.5 ! misho     273:     const char *errstr;
1.1       misho     274:     uid_t uid;
1.1.1.5 ! misho     275:     debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)
1.1       misho     276: 
1.1.1.5 ! misho     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));
1.1       misho     284: }
                    285: 
                    286: void
                    287: sudo_setpwent(void)
                    288: {
1.1.1.2   misho     289:     debug_decl(sudo_setpwent, SUDO_DEBUG_NSS)
                    290: 
1.1       misho     291:     setpwent();
                    292:     if (pwcache_byuid == NULL)
                    293:        pwcache_byuid = rbcreate(cmp_pwuid);
                    294:     if (pwcache_byname == NULL)
                    295:        pwcache_byname = rbcreate(cmp_pwnam);
1.1.1.2   misho     296: 
                    297:     debug_return;
1.1       misho     298: }
                    299: 
                    300: void
                    301: sudo_freepwcache(void)
                    302: {
1.1.1.2   misho     303:     debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS)
                    304: 
1.1       misho     305:     if (pwcache_byuid != NULL) {
1.1.1.3   misho     306:        rbdestroy(pwcache_byuid, sudo_pw_delref_item);
1.1       misho     307:        pwcache_byuid = NULL;
                    308:     }
                    309:     if (pwcache_byname != NULL) {
1.1.1.3   misho     310:        rbdestroy(pwcache_byname, sudo_pw_delref_item);
1.1       misho     311:        pwcache_byname = NULL;
                    312:     }
1.1.1.2   misho     313: 
                    314:     debug_return;
1.1       misho     315: }
                    316: 
                    317: void
                    318: sudo_endpwent(void)
                    319: {
1.1.1.2   misho     320:     debug_decl(sudo_endpwent, SUDO_DEBUG_NSS)
                    321: 
1.1       misho     322:     endpwent();
                    323:     sudo_freepwcache();
1.1.1.2   misho     324: 
                    325:     debug_return;
1.1       misho     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
1.1.1.3   misho     340: sudo_gr_addref(struct group *gr)
1.1       misho     341: {
1.1.1.3   misho     342:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
1.1       misho     343:     ptr_to_item(gr)->refcnt++;
1.1.1.2   misho     344:     debug_return;
1.1       misho     345: }
                    346: 
                    347: static void
1.1.1.3   misho     348: sudo_gr_delref_item(void *v)
1.1       misho     349: {
                    350:     struct cache_item *item = v;
1.1.1.3   misho     351:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
1.1       misho     352: 
                    353:     if (--item->refcnt == 0)
                    354:        efree(item);
1.1.1.2   misho     355: 
                    356:     debug_return;
1.1       misho     357: }
                    358: 
                    359: void
1.1.1.3   misho     360: sudo_gr_delref(struct group *gr)
1.1       misho     361: {
1.1.1.3   misho     362:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
                    363:     sudo_gr_delref_item(ptr_to_item(gr));
1.1.1.2   misho     364:     debug_return;
1.1       misho     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;
1.1.1.2   misho     375:     debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS)
1.1       misho     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:      */
1.1.1.4   misho     385:     item = sudo_make_gritem(gid, NULL);
                    386:     if (item == NULL) {
1.1.1.2   misho     387:        item = ecalloc(1, sizeof(*item));
1.1       misho     388:        item->refcnt = 1;
                    389:        item->k.gid = gid;
1.1.1.2   misho     390:        /* item->d.gr = NULL; */
1.1       misho     391:     }
1.1.1.4   misho     392:     if (rbinsert(grcache_bygid, item) != NULL)
1.1.1.5 ! misho     393:        fatalx(U_("unable to cache gid %u, already exists"),
1.1.1.4   misho     394:            (unsigned int) gid);
1.1       misho     395: done:
                    396:     item->refcnt++;
1.1.1.2   misho     397:     debug_return_ptr(item->d.gr);
1.1       misho     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;
1.1.1.2   misho     409:     debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS)
1.1       misho     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:      */
1.1.1.4   misho     419:     item = sudo_make_gritem((gid_t)-1, name);
                    420:     if (item == NULL) {
1.1       misho     421:        len = strlen(name) + 1;
1.1.1.2   misho     422:        item = ecalloc(1, sizeof(*item) + len);
1.1       misho     423:        item->refcnt = 1;
                    424:        item->k.name = (char *) item + sizeof(*item);
                    425:        memcpy(item->k.name, name, len);
1.1.1.2   misho     426:        /* item->d.gr = NULL; */
1.1       misho     427:     }
1.1.1.4   misho     428:     if (rbinsert(grcache_byname, item) != NULL)
1.1.1.5 ! misho     429:        fatalx(U_("unable to cache group %s, already exists"), name);
1.1       misho     430: done:
                    431:     item->refcnt++;
1.1.1.2   misho     432:     debug_return_ptr(item->d.gr);
1.1       misho     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: {
1.1.1.2   misho     441:     struct cache_item_gr *gritem;
1.1.1.5 ! misho     442:     const char *errstr;
1.1       misho     443:     struct group *gr;
                    444:     struct rbnode *node;
1.1.1.4   misho     445:     size_t len, name_len;
1.1       misho     446:     int i;
1.1.1.2   misho     447:     debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
1.1       misho     448: 
1.1.1.4   misho     449:     name_len = strlen(group);
                    450:     len = sizeof(*gritem) + name_len + 1;
1.1       misho     451: 
                    452:     for (i = 0; i < 2; i++) {
1.1.1.2   misho     453:        gritem = ecalloc(1, len);
                    454:        gr = &gritem->gr;
1.1.1.5 ! misho     455:        gr->gr_gid = (gid_t) atoid(group + 1, NULL, NULL, &errstr);
1.1.1.2   misho     456:        gr->gr_name = (char *)(gritem + 1);
1.1.1.4   misho     457:        memcpy(gr->gr_name, group, name_len + 1);
1.1.1.5 ! misho     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:        }
1.1       misho     464: 
1.1.1.2   misho     465:        gritem->cache.refcnt = 1;
                    466:        gritem->cache.d.gr = gr;
1.1       misho     467:        if (i == 0) {
1.1.1.4   misho     468:            /* Store by gid if it doesn't already exist. */
1.1.1.2   misho     469:            gritem->cache.k.gid = gr->gr_gid;
                    470:            if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
1.1.1.4   misho     471:                /* Already exists, free the item we created. */
                    472:                efree(gritem);
                    473:                gritem = (struct cache_item_gr *) node->data;
1.1       misho     474:            }
                    475:        } else {
                    476:            /* Store by name, overwriting cached version. */
1.1.1.2   misho     477:            gritem->cache.k.name = gr->gr_name;
                    478:            if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
1.1.1.4   misho     479:                /* Already exists, free the item we created. */
                    480:                efree(gritem);
                    481:                gritem = (struct cache_item_gr *) node->data;
1.1       misho     482:            }
                    483:        }
                    484:     }
1.1.1.2   misho     485:     gritem->cache.refcnt++;
1.1.1.4   misho     486:     debug_return_ptr(&gritem->gr);
1.1       misho     487: }
                    488: 
                    489: void
1.1.1.3   misho     490: sudo_grlist_addref(struct group_list *grlist)
1.1       misho     491: {
1.1.1.3   misho     492:     debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
1.1       misho     493:     ptr_to_item(grlist)->refcnt++;
1.1.1.2   misho     494:     debug_return;
1.1       misho     495: }
                    496: 
                    497: static void
1.1.1.3   misho     498: sudo_grlist_delref_item(void *v)
1.1       misho     499: {
                    500:     struct cache_item *item = v;
1.1.1.3   misho     501:     debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
1.1       misho     502: 
                    503:     if (--item->refcnt == 0)
                    504:        efree(item);
1.1.1.2   misho     505: 
                    506:     debug_return;
1.1       misho     507: }
                    508: 
                    509: void
1.1.1.3   misho     510: sudo_grlist_delref(struct group_list *grlist)
1.1       misho     511: {
1.1.1.3   misho     512:     debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
                    513:     sudo_grlist_delref_item(ptr_to_item(grlist));
1.1.1.2   misho     514:     debug_return;
1.1       misho     515: }
                    516: 
                    517: void
                    518: sudo_setgrent(void)
                    519: {
1.1.1.2   misho     520:     debug_decl(sudo_setgrent, SUDO_DEBUG_NSS)
                    521: 
1.1       misho     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);
1.1.1.2   misho     529: 
                    530:     debug_return;
1.1       misho     531: }
                    532: 
                    533: void
                    534: sudo_freegrcache(void)
                    535: {
1.1.1.2   misho     536:     debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS)
                    537: 
1.1       misho     538:     if (grcache_bygid != NULL) {
1.1.1.3   misho     539:        rbdestroy(grcache_bygid, sudo_gr_delref_item);
1.1       misho     540:        grcache_bygid = NULL;
                    541:     }
                    542:     if (grcache_byname != NULL) {
1.1.1.3   misho     543:        rbdestroy(grcache_byname, sudo_gr_delref_item);
1.1       misho     544:        grcache_byname = NULL;
                    545:     }
                    546:     if (grlist_cache != NULL) {
1.1.1.3   misho     547:        rbdestroy(grlist_cache, sudo_grlist_delref_item);
1.1       misho     548:        grlist_cache = NULL;
                    549:     }
1.1.1.2   misho     550: 
                    551:     debug_return;
1.1       misho     552: }
                    553: 
                    554: void
                    555: sudo_endgrent(void)
                    556: {
1.1.1.2   misho     557:     debug_decl(sudo_endgrent, SUDO_DEBUG_NSS)
                    558: 
1.1       misho     559:     endgrent();
                    560:     sudo_freegrcache();
1.1.1.2   misho     561: 
                    562:     debug_return;
1.1       misho     563: }
                    564: 
                    565: struct group_list *
1.1.1.5 ! misho     566: sudo_get_grlist(const struct passwd *pw)
1.1       misho     567: {
                    568:     struct cache_item key, *item;
                    569:     struct rbnode *node;
                    570:     size_t len;
1.1.1.3   misho     571:     debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)
1.1       misho     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:      */
1.1.1.4   misho     581:     item = sudo_make_grlist_item(pw, NULL, NULL);
                    582:     if (item == NULL) {
1.1       misho     583:        /* Should not happen. */
                    584:        len = strlen(pw->pw_name) + 1;
1.1.1.2   misho     585:        item = ecalloc(1, sizeof(*item) + len);
1.1       misho     586:        item->refcnt = 1;
                    587:        item->k.name = (char *) item + sizeof(*item);
                    588:        memcpy(item->k.name, pw->pw_name, len);
1.1.1.2   misho     589:        /* item->d.grlist = NULL; */
1.1       misho     590:     }
1.1.1.4   misho     591:     if (rbinsert(grlist_cache, item) != NULL)
1.1.1.5 ! misho     592:        fatalx(U_("unable to cache group list for %s, already exists"),
1.1.1.4   misho     593:            pw->pw_name);
1.1       misho     594: done:
                    595:     item->refcnt++;
1.1.1.2   misho     596:     debug_return_ptr(item->d.grlist);
1.1       misho     597: }
                    598: 
1.1.1.4   misho     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)
1.1.1.5 ! misho     612:            fatalx(U_("unable to parse groups for %s"), pw->pw_name);
1.1.1.4   misho     613:        if (rbinsert(grlist_cache, item) != NULL)
1.1.1.5 ! misho     614:            fatalx(U_("unable to cache group list for %s, already exists"),
1.1.1.4   misho     615:                pw->pw_name);
                    616:     }
                    617:     debug_return;
                    618: }
                    619: 
1.1.1.2   misho     620: bool
1.1.1.5 ! misho     621: user_in_group(const struct passwd *pw, const char *group)
1.1       misho     622: {
                    623:     struct group_list *grlist;
                    624:     struct group *grp = NULL;
1.1.1.5 ! misho     625:     const char *errstr;
1.1.1.2   misho     626:     int i;
                    627:     bool matched = false;
                    628:     debug_decl(user_in_group, SUDO_DEBUG_NSS)
1.1       misho     629: 
1.1.1.3   misho     630:     if ((grlist = sudo_get_grlist(pw)) != NULL) {
1.1       misho     631:        /*
                    632:         * If it could be a sudo-style group ID check gids first.
                    633:         */
                    634:        if (group[0] == '#') {
1.1.1.5 ! misho     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) {
1.1.1.2   misho     641:                    matched = true;
1.1       misho     642:                    goto done;
                    643:                }
1.1.1.5 ! misho     644:                for (i = 0; i < grlist->ngids; i++) {
        !           645:                    if (gid == grlist->gids[i]) {
        !           646:                        matched = true;
        !           647:                        goto done;
        !           648:                    }
        !           649:                }
1.1       misho     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) {
1.1.1.2   misho     659:                matched = true;
1.1       misho     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) {
1.1.1.2   misho     667:                matched = true;
1.1       misho     668:                goto done;
                    669:            }
                    670:        }
                    671: done:
                    672:        if (grp != NULL)
1.1.1.3   misho     673:            sudo_gr_delref(grp);
                    674:        sudo_grlist_delref(grlist);
1.1       misho     675:     }
1.1.1.2   misho     676:     debug_return_bool(matched);
1.1       misho     677: }

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