Annotation of embedaddon/sudo/compat/getgrouplist.c, revision 1.1.1.3

1.1       misho       1: /*
1.1.1.2   misho       2:  * Copyright (c) 2010, 2011, 2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16: 
                     17: #include <config.h>
                     18: 
1.1.1.2   misho      19: #ifndef HAVE_GETGROUPLIST
                     20: 
1.1       misho      21: #include <sys/types.h>
                     22: #include <stdio.h>
                     23: #ifdef STDC_HEADERS
                     24: # include <stdlib.h>
                     25: # include <stddef.h>
                     26: #else
                     27: # ifdef HAVE_STDLIB_H
                     28: #  include <stdlib.h>
                     29: # endif
                     30: #endif /* STDC_HEADERS */
                     31: #ifdef HAVE_STRING_H
                     32: # include <string.h>
                     33: #endif /* HAVE_STRING_H */
                     34: #ifdef HAVE_STRINGS_H
                     35: # include <strings.h>
                     36: #endif /* HAVE_STRINGS_H */
                     37: #include <grp.h>
1.1.1.2   misho      38: #ifdef HAVE_NSS_SEARCH
                     39: # include <limits.h>
                     40: # include <nsswitch.h>
                     41: # ifdef HAVE_NSS_DBDEFS_H
                     42: #  include <nss_dbdefs.h>
                     43: # else
                     44: #  include "compat/nss_dbdefs.h"
                     45: # endif
                     46: #endif
1.1       misho      47: 
                     48: #include "missing.h"
                     49: 
1.1.1.2   misho      50: #if defined(HAVE_GETGRSET)
1.1       misho      51: /*
                     52:  * BSD-compatible getgrouplist(3) using getgrset(3)
                     53:  */
                     54: int
                     55: getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
                     56: {
                     57:     char *cp, *grset = NULL;
                     58:     int i, ngroups = 1;
                     59:     int grpsize = *ngroupsp;
                     60:     int rval = -1;
                     61:     gid_t gid;
                     62: 
                     63:     /* We support BSD semantics where the first element is the base gid */
                     64:     if (grpsize <= 0)
                     65:        return -1;
                     66:     groups[0] = basegid;
                     67: 
                     68: #ifdef HAVE_SETAUTHDB
                     69:     aix_setauthdb((char *) name);
                     70: #endif
                     71:     if ((grset = getgrset(name)) != NULL) {
                     72:        for (cp = strtok(grset, ","); cp != NULL; cp = strtok(NULL, ",")) {
                     73:            gid = atoi(cp);
                     74:            if (gid != basegid) {
                     75:                if (ngroups == grpsize)
                     76:                    goto done;
                     77:                groups[ngroups++] = gid;
                     78:            }
                     79:        }
                     80:     }
                     81:     rval = 0;
                     82: 
                     83: done:
1.1.1.2   misho      84:     free(grset);
1.1       misho      85: #ifdef HAVE_SETAUTHDB
                     86:     aix_restoreauthdb();
                     87: #endif
                     88:     *ngroupsp = ngroups;
                     89: 
                     90:     return rval;
                     91: }
                     92: 
1.1.1.2   misho      93: #elif defined(HAVE_NSS_SEARCH)
                     94: 
                     95: #ifndef ALIGNBYTES
                     96: # define ALIGNBYTES    (sizeof(long) - 1L)
                     97: #endif
                     98: #ifndef ALIGN
                     99: # define ALIGN(p)      (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
                    100: #endif
                    101: 
                    102: extern void _nss_initf_group(nss_db_params_t *);
                    103: 
1.1.1.3 ! misho     104: static id_t
        !           105: strtoid(const char *p, int *errval)
        !           106: {
        !           107:     char *ep;
        !           108:     id_t rval = 0;
        !           109: 
        !           110:     errno = 0;
        !           111:     if (*p == '-') {
        !           112:        long lval = strtol(p, &ep, 10);
        !           113:        if (ep == p || *ep != '\0') {
        !           114:            *errval = EINVAL;
        !           115:            goto done;
        !           116:        }
        !           117:        if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) ||
        !           118:            (lval > INT_MAX || lval < INT_MIN)) {
        !           119:            *errval = ERANGE;
        !           120:            goto done;
        !           121:        }
        !           122:        rval = (id_t)lval;
        !           123:        *errval = 0;
        !           124:     } else {
        !           125:        unsigned long ulval = strtoul(p, &ep, 10);
        !           126:        if (ep == p || *ep != '\0') {
        !           127:            *errval = EINVAL;
        !           128:            goto done;
        !           129:        }
        !           130:        if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) {
        !           131:            *errval = ERANGE;
        !           132:            goto done;
        !           133:        }
        !           134:        rval = (id_t)ulval;
        !           135:        *errval = 0;
        !           136:     }
        !           137: done:
        !           138:     return rval;
        !           139: }
        !           140: 
1.1.1.2   misho     141: /*
                    142:  * Convert a groups file string (instr) to a struct group (ent) using
                    143:  * buf for storage.  
                    144:  */
                    145: static int
                    146: str2grp(const char *instr, int inlen, void *ent, char *buf, int buflen)
                    147: {
                    148:     struct group *grp = ent;
1.1.1.3 ! misho     149:     char *cp, *fieldsep = buf;
1.1.1.2   misho     150:     char **gr_mem, **gr_end;
1.1.1.3 ! misho     151:     int errval, yp = 0;
        !           152:     id_t id;
1.1.1.2   misho     153: 
                    154:     /* Must at least have space to copy instr -> buf. */
                    155:     if (inlen >= buflen)
                    156:        return NSS_STR_PARSE_ERANGE;
                    157: 
                    158:     /* Paranoia: buf and instr should be distinct. */
                    159:     if (buf != instr) {
                    160:        memmove(buf, instr, inlen);
                    161:        buf[inlen] = '\0';
                    162:     }
                    163: 
                    164:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    165:        return NSS_STR_PARSE_PARSE;
                    166:     *fieldsep++ = '\0';
                    167:     grp->gr_name = cp;
                    168: 
                    169:     /* Check for YP inclusion/exclusion entries. */
                    170:     if (*cp == '+' || *cp == '-') {
                    171:        /* Only the name is required for YP inclusion/exclusion entries. */
                    172:        grp->gr_passwd = "";
                    173:        grp->gr_gid = 0;
                    174:        grp->gr_mem = NULL;
                    175:        yp = 1;
                    176:     }
                    177: 
                    178:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    179:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
                    180:     *fieldsep++ = '\0';
                    181:     grp->gr_passwd = cp;
                    182: 
                    183:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    184:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
                    185:     *fieldsep++ = '\0';
1.1.1.3 ! misho     186:     id = strtoid(cp, &errval);
        !           187:     if (errval != 0) {
        !           188:        /*
        !           189:         * A range error is always a fatal error, but ignore garbage
        !           190:         * at the end of YP entries since it has no meaning.
        !           191:         */
        !           192:        if (errval == ERANGE)
        !           193:            return NSS_STR_PARSE_ERANGE;
1.1.1.2   misho     194:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
1.1.1.3 ! misho     195:     }
1.1.1.2   misho     196: #ifdef GID_NOBODY
1.1.1.3 ! misho     197:     /* Negative gids get mapped to nobody on Solaris. */
        !           198:     if (*cp == '-' && id != 0)
1.1.1.2   misho     199:        grp->gr_gid = GID_NOBODY;
1.1.1.3 ! misho     200:     else
1.1.1.2   misho     201: #endif
1.1.1.3 ! misho     202:        grp->gr_gid = (gid_t)id;
1.1.1.2   misho     203: 
                    204:     /* Store group members, taking care to use proper alignment. */
                    205:     grp->gr_mem = NULL;
                    206:     if (*fieldsep != '\0') {
                    207:        grp->gr_mem = gr_mem = (char **)ALIGN(buf + inlen + 1);
                    208:        gr_end = (char **)((unsigned long)(buf + buflen) & ~ALIGNBYTES);
                    209:        for (;;) {
                    210:            if (gr_mem == gr_end)
                    211:                return NSS_STR_PARSE_ERANGE;    /* out of space! */
                    212:            *gr_mem++ = cp;
                    213:            if (fieldsep == NULL)
                    214:                break;
                    215:            if ((fieldsep = strchr(cp = fieldsep, ',')) != NULL)
                    216:                *fieldsep++ = '\0';
                    217:        }
                    218:        *gr_mem = NULL;
                    219:     }
                    220:     return NSS_STR_PARSE_SUCCESS;
                    221: }
                    222: 
                    223: static nss_status_t
                    224: process_cstr(const char *instr, int inlen, struct nss_groupsbymem *gbm)
                    225: {
                    226:     const char *user = gbm->username;
                    227:     nss_status_t rval = NSS_NOTFOUND;
                    228:     nss_XbyY_buf_t *buf;
                    229:     struct group *grp;
                    230:     char **gr_mem;
                    231:     int        error, i;
                    232: 
                    233:     buf = _nss_XbyY_buf_alloc(sizeof(struct group), NSS_BUFLEN_GROUP);
                    234:     if (buf == NULL)
                    235:        return NSS_UNAVAIL;
                    236: 
                    237:     /* Parse groups file string -> struct group. */
                    238:     grp = buf->result;
                    239:     error = (*gbm->str2ent)(instr, inlen, grp, buf->buffer, buf->buflen);
                    240:     if (error || grp->gr_mem == NULL)
                    241:        goto done;
                    242: 
                    243:     for (gr_mem = grp->gr_mem; *gr_mem != NULL; gr_mem++) {
                    244:        if (strcmp(*gr_mem, user) == 0) {
                    245:            /* Append to gid_array unless gr_gid is a dupe. */
                    246:            for (i = 0; i < gbm->numgids; i++) {
                    247:                if (gbm->gid_array[i] == grp->gr_gid)
                    248:                    goto done;                  /* already present */
                    249:            }
                    250:            /* Store gid if there is space. */
                    251:            if (i < gbm->maxgids)
                    252:                gbm->gid_array[i] = grp->gr_gid;
                    253:            /* Always increment numgids so we can detect when out of space. */
                    254:            gbm->numgids++;
                    255:            goto done;
                    256:        }
                    257:     }
                    258: done:
                    259:     _nss_XbyY_buf_free(buf);
                    260:     return rval;
                    261: }
                    262: 
                    263: /*
                    264:  * BSD-compatible getgrouplist(3) using nss_search(3)
                    265:  */
                    266: int
                    267: getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
                    268: {
                    269:     struct nss_groupsbymem gbm;
                    270:     static DEFINE_NSS_DB_ROOT(db_root);
                    271: 
                    272:     /* We support BSD semantics where the first element is the base gid */
                    273:     if (*ngroupsp <= 0)
                    274:        return -1;
                    275:     groups[0] = basegid;
                    276: 
                    277:     memset(&gbm, 0, sizeof(gbm));
                    278:     gbm.username = name;
                    279:     gbm.gid_array = groups;
                    280:     gbm.maxgids = *ngroupsp;
                    281:     gbm.numgids = 1; /* for basegid */
                    282:     gbm.force_slow_way = 1;
                    283:     gbm.str2ent = str2grp;
                    284:     gbm.process_cstr = process_cstr;
                    285: 
                    286:     /*
                    287:      * Can't use nss_search return value since it may return NSS_UNAVAIL
                    288:      * when no nsswitch.conf entry (e.g. compat mode).
                    289:      */
                    290:     (void)nss_search(&db_root, _nss_initf_group, NSS_DBOP_GROUP_BYMEMBER, &gbm);
                    291: 
                    292:     if (gbm.numgids <= gbm.maxgids) {
                    293:         *ngroupsp = gbm.numgids;
                    294:         return 0;
                    295:     }
                    296:     *ngroupsp = gbm.maxgids;
                    297:     return -1;
                    298: }
                    299: 
                    300: #else /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
1.1       misho     301: 
                    302: /*
                    303:  * BSD-compatible getgrouplist(3) using getgrent(3)
                    304:  */
                    305: int
                    306: getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
                    307: {
                    308:     int i, ngroups = 1;
                    309:     int grpsize = *ngroupsp;
                    310:     int rval = -1;
                    311:     struct group *grp;
                    312: 
                    313:     /* We support BSD semantics where the first element is the base gid */
                    314:     if (grpsize <= 0)
                    315:        return -1;
                    316:     groups[0] = basegid;
                    317: 
                    318:     setgrent();
                    319:     while ((grp = getgrent()) != NULL) {
                    320:        if (grp->gr_gid == basegid)
                    321:            continue;
                    322: 
                    323:        for (i = 0; grp->gr_mem[i] != NULL; i++) {
                    324:            if (strcmp(name, grp->gr_mem[i]) == 0)
                    325:                break;
                    326:        }
                    327:        if (grp->gr_mem[i] == NULL)
                    328:            continue; /* user not found */
                    329: 
                    330:        /* Only add if it is not the same as an existing gid */
                    331:        for (i = 0; i < ngroups; i++) {
                    332:            if (grp->gr_gid == groups[i])
                    333:                break;
                    334:        }
                    335:        if (i == ngroups) {
                    336:            if (ngroups == grpsize)
                    337:                goto done;
                    338:            groups[ngroups++] = grp->gr_gid;
                    339:        }
                    340:     }
                    341:     rval = 0;
                    342: 
                    343: done:
                    344:     endgrent();
                    345:     *ngroupsp = ngroups;
                    346: 
                    347:     return rval;
                    348: }
1.1.1.2   misho     349: #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
                    350: #endif /* HAVE_GETGROUPLIST */

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