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

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) {
1.1.1.4 ! misho      72:        const char *errstr;
1.1       misho      73:        for (cp = strtok(grset, ","); cp != NULL; cp = strtok(NULL, ",")) {
1.1.1.4 ! misho      74:            gid = atoid(cp, NULL, NULL, &errstr);
        !            75:            if (errstr == NULL && gid != basegid) {
1.1       misho      76:                if (ngroups == grpsize)
                     77:                    goto done;
                     78:                groups[ngroups++] = gid;
                     79:            }
                     80:        }
                     81:     }
                     82:     rval = 0;
                     83: 
                     84: done:
1.1.1.2   misho      85:     free(grset);
1.1       misho      86: #ifdef HAVE_SETAUTHDB
                     87:     aix_restoreauthdb();
                     88: #endif
                     89:     *ngroupsp = ngroups;
                     90: 
                     91:     return rval;
                     92: }
                     93: 
1.1.1.2   misho      94: #elif defined(HAVE_NSS_SEARCH)
                     95: 
                     96: #ifndef ALIGNBYTES
                     97: # define ALIGNBYTES    (sizeof(long) - 1L)
                     98: #endif
                     99: #ifndef ALIGN
                    100: # define ALIGN(p)      (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
                    101: #endif
                    102: 
                    103: extern void _nss_initf_group(nss_db_params_t *);
                    104: 
1.1.1.3   misho     105: static id_t
                    106: strtoid(const char *p, int *errval)
                    107: {
                    108:     char *ep;
                    109:     id_t rval = 0;
                    110: 
                    111:     errno = 0;
                    112:     if (*p == '-') {
                    113:        long lval = strtol(p, &ep, 10);
                    114:        if (ep == p || *ep != '\0') {
                    115:            *errval = EINVAL;
                    116:            goto done;
                    117:        }
                    118:        if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) ||
                    119:            (lval > INT_MAX || lval < INT_MIN)) {
                    120:            *errval = ERANGE;
                    121:            goto done;
                    122:        }
                    123:        rval = (id_t)lval;
                    124:        *errval = 0;
                    125:     } else {
                    126:        unsigned long ulval = strtoul(p, &ep, 10);
                    127:        if (ep == p || *ep != '\0') {
                    128:            *errval = EINVAL;
                    129:            goto done;
                    130:        }
                    131:        if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) {
                    132:            *errval = ERANGE;
                    133:            goto done;
                    134:        }
                    135:        rval = (id_t)ulval;
                    136:        *errval = 0;
                    137:     }
                    138: done:
                    139:     return rval;
                    140: }
                    141: 
1.1.1.2   misho     142: /*
                    143:  * Convert a groups file string (instr) to a struct group (ent) using
                    144:  * buf for storage.  
                    145:  */
                    146: static int
                    147: str2grp(const char *instr, int inlen, void *ent, char *buf, int buflen)
                    148: {
                    149:     struct group *grp = ent;
1.1.1.3   misho     150:     char *cp, *fieldsep = buf;
1.1.1.2   misho     151:     char **gr_mem, **gr_end;
1.1.1.3   misho     152:     int errval, yp = 0;
                    153:     id_t id;
1.1.1.2   misho     154: 
                    155:     /* Must at least have space to copy instr -> buf. */
                    156:     if (inlen >= buflen)
                    157:        return NSS_STR_PARSE_ERANGE;
                    158: 
                    159:     /* Paranoia: buf and instr should be distinct. */
                    160:     if (buf != instr) {
                    161:        memmove(buf, instr, inlen);
                    162:        buf[inlen] = '\0';
                    163:     }
                    164: 
                    165:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    166:        return NSS_STR_PARSE_PARSE;
                    167:     *fieldsep++ = '\0';
                    168:     grp->gr_name = cp;
                    169: 
                    170:     /* Check for YP inclusion/exclusion entries. */
                    171:     if (*cp == '+' || *cp == '-') {
                    172:        /* Only the name is required for YP inclusion/exclusion entries. */
                    173:        grp->gr_passwd = "";
                    174:        grp->gr_gid = 0;
                    175:        grp->gr_mem = NULL;
                    176:        yp = 1;
                    177:     }
                    178: 
                    179:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    180:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
                    181:     *fieldsep++ = '\0';
                    182:     grp->gr_passwd = cp;
                    183: 
                    184:     if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
                    185:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
                    186:     *fieldsep++ = '\0';
1.1.1.3   misho     187:     id = strtoid(cp, &errval);
                    188:     if (errval != 0) {
                    189:        /*
                    190:         * A range error is always a fatal error, but ignore garbage
                    191:         * at the end of YP entries since it has no meaning.
                    192:         */
                    193:        if (errval == ERANGE)
                    194:            return NSS_STR_PARSE_ERANGE;
1.1.1.2   misho     195:        return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
1.1.1.3   misho     196:     }
1.1.1.2   misho     197: #ifdef GID_NOBODY
1.1.1.3   misho     198:     /* Negative gids get mapped to nobody on Solaris. */
                    199:     if (*cp == '-' && id != 0)
1.1.1.2   misho     200:        grp->gr_gid = GID_NOBODY;
1.1.1.3   misho     201:     else
1.1.1.2   misho     202: #endif
1.1.1.3   misho     203:        grp->gr_gid = (gid_t)id;
1.1.1.2   misho     204: 
                    205:     /* Store group members, taking care to use proper alignment. */
                    206:     grp->gr_mem = NULL;
                    207:     if (*fieldsep != '\0') {
                    208:        grp->gr_mem = gr_mem = (char **)ALIGN(buf + inlen + 1);
                    209:        gr_end = (char **)((unsigned long)(buf + buflen) & ~ALIGNBYTES);
                    210:        for (;;) {
                    211:            if (gr_mem == gr_end)
                    212:                return NSS_STR_PARSE_ERANGE;    /* out of space! */
                    213:            *gr_mem++ = cp;
                    214:            if (fieldsep == NULL)
                    215:                break;
                    216:            if ((fieldsep = strchr(cp = fieldsep, ',')) != NULL)
                    217:                *fieldsep++ = '\0';
                    218:        }
                    219:        *gr_mem = NULL;
                    220:     }
                    221:     return NSS_STR_PARSE_SUCCESS;
                    222: }
                    223: 
                    224: static nss_status_t
                    225: process_cstr(const char *instr, int inlen, struct nss_groupsbymem *gbm)
                    226: {
                    227:     const char *user = gbm->username;
                    228:     nss_status_t rval = NSS_NOTFOUND;
                    229:     nss_XbyY_buf_t *buf;
                    230:     struct group *grp;
                    231:     char **gr_mem;
                    232:     int        error, i;
                    233: 
                    234:     buf = _nss_XbyY_buf_alloc(sizeof(struct group), NSS_BUFLEN_GROUP);
                    235:     if (buf == NULL)
                    236:        return NSS_UNAVAIL;
                    237: 
                    238:     /* Parse groups file string -> struct group. */
                    239:     grp = buf->result;
                    240:     error = (*gbm->str2ent)(instr, inlen, grp, buf->buffer, buf->buflen);
                    241:     if (error || grp->gr_mem == NULL)
                    242:        goto done;
                    243: 
                    244:     for (gr_mem = grp->gr_mem; *gr_mem != NULL; gr_mem++) {
                    245:        if (strcmp(*gr_mem, user) == 0) {
                    246:            /* Append to gid_array unless gr_gid is a dupe. */
                    247:            for (i = 0; i < gbm->numgids; i++) {
                    248:                if (gbm->gid_array[i] == grp->gr_gid)
                    249:                    goto done;                  /* already present */
                    250:            }
                    251:            /* Store gid if there is space. */
                    252:            if (i < gbm->maxgids)
                    253:                gbm->gid_array[i] = grp->gr_gid;
                    254:            /* Always increment numgids so we can detect when out of space. */
                    255:            gbm->numgids++;
                    256:            goto done;
                    257:        }
                    258:     }
                    259: done:
                    260:     _nss_XbyY_buf_free(buf);
                    261:     return rval;
                    262: }
                    263: 
                    264: /*
                    265:  * BSD-compatible getgrouplist(3) using nss_search(3)
                    266:  */
                    267: int
                    268: getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
                    269: {
                    270:     struct nss_groupsbymem gbm;
                    271:     static DEFINE_NSS_DB_ROOT(db_root);
                    272: 
                    273:     /* We support BSD semantics where the first element is the base gid */
                    274:     if (*ngroupsp <= 0)
                    275:        return -1;
                    276:     groups[0] = basegid;
                    277: 
                    278:     memset(&gbm, 0, sizeof(gbm));
                    279:     gbm.username = name;
                    280:     gbm.gid_array = groups;
                    281:     gbm.maxgids = *ngroupsp;
                    282:     gbm.numgids = 1; /* for basegid */
                    283:     gbm.force_slow_way = 1;
                    284:     gbm.str2ent = str2grp;
                    285:     gbm.process_cstr = process_cstr;
                    286: 
                    287:     /*
                    288:      * Can't use nss_search return value since it may return NSS_UNAVAIL
                    289:      * when no nsswitch.conf entry (e.g. compat mode).
                    290:      */
                    291:     (void)nss_search(&db_root, _nss_initf_group, NSS_DBOP_GROUP_BYMEMBER, &gbm);
                    292: 
                    293:     if (gbm.numgids <= gbm.maxgids) {
                    294:         *ngroupsp = gbm.numgids;
                    295:         return 0;
                    296:     }
                    297:     *ngroupsp = gbm.maxgids;
                    298:     return -1;
                    299: }
                    300: 
                    301: #else /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
1.1       misho     302: 
                    303: /*
                    304:  * BSD-compatible getgrouplist(3) using getgrent(3)
                    305:  */
                    306: int
                    307: getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
                    308: {
                    309:     int i, ngroups = 1;
                    310:     int grpsize = *ngroupsp;
                    311:     int rval = -1;
                    312:     struct group *grp;
                    313: 
                    314:     /* We support BSD semantics where the first element is the base gid */
                    315:     if (grpsize <= 0)
                    316:        return -1;
                    317:     groups[0] = basegid;
                    318: 
                    319:     setgrent();
                    320:     while ((grp = getgrent()) != NULL) {
1.1.1.4 ! misho     321:        if (grp->gr_gid == basegid || grp->gr_mem == NULL)
1.1       misho     322:            continue;
                    323: 
                    324:        for (i = 0; grp->gr_mem[i] != NULL; i++) {
                    325:            if (strcmp(name, grp->gr_mem[i]) == 0)
                    326:                break;
                    327:        }
                    328:        if (grp->gr_mem[i] == NULL)
                    329:            continue; /* user not found */
                    330: 
                    331:        /* Only add if it is not the same as an existing gid */
                    332:        for (i = 0; i < ngroups; i++) {
                    333:            if (grp->gr_gid == groups[i])
                    334:                break;
                    335:        }
                    336:        if (i == ngroups) {
                    337:            if (ngroups == grpsize)
                    338:                goto done;
                    339:            groups[ngroups++] = grp->gr_gid;
                    340:        }
                    341:     }
                    342:     rval = 0;
                    343: 
                    344: done:
                    345:     endgrent();
                    346:     *ngroupsp = ngroups;
                    347: 
                    348:     return rval;
                    349: }
1.1.1.2   misho     350: #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
                    351: #endif /* HAVE_GETGROUPLIST */

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