File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / getgrouplist.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:56:33 2013 UTC (10 years, 8 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, HEAD
v 1.8.8

    1: /*
    2:  * Copyright (c) 2010, 2011, 2013 Todd C. Miller <Todd.Miller@courtesan.com>
    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: 
   19: #ifndef HAVE_GETGROUPLIST
   20: 
   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>
   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
   47: 
   48: #include "missing.h"
   49: 
   50: #if defined(HAVE_GETGRSET)
   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:
   84:     free(grset);
   85: #ifdef HAVE_SETAUTHDB
   86:     aix_restoreauthdb();
   87: #endif
   88:     *ngroupsp = ngroups;
   89: 
   90:     return rval;
   91: }
   92: 
   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: 
  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: 
  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;
  149:     char *cp, *fieldsep = buf;
  150:     char **gr_mem, **gr_end;
  151:     int errval, yp = 0;
  152:     id_t id;
  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';
  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;
  194: 	return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
  195:     }
  196: #ifdef GID_NOBODY
  197:     /* Negative gids get mapped to nobody on Solaris. */
  198:     if (*cp == '-' && id != 0)
  199: 	grp->gr_gid = GID_NOBODY;
  200:     else
  201: #endif
  202: 	grp->gr_gid = (gid_t)id;
  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 */
  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: }
  349: #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
  350: #endif /* HAVE_GETGROUPLIST */

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