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

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

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