File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / getgrouplist.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 1 month ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    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: 	const char *errstr;
   73: 	for (cp = strtok(grset, ","); cp != NULL; cp = strtok(NULL, ",")) {
   74: 	    gid = atoid(cp, NULL, NULL, &errstr);
   75: 	    if (errstr == NULL && gid != basegid) {
   76: 		if (ngroups == grpsize)
   77: 		    goto done;
   78: 		groups[ngroups++] = gid;
   79: 	    }
   80: 	}
   81:     }
   82:     rval = 0;
   83: 
   84: done:
   85:     free(grset);
   86: #ifdef HAVE_SETAUTHDB
   87:     aix_restoreauthdb();
   88: #endif
   89:     *ngroupsp = ngroups;
   90: 
   91:     return rval;
   92: }
   93: 
   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: 
  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: 
  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;
  150:     char *cp, *fieldsep = buf;
  151:     char **gr_mem, **gr_end;
  152:     int errval, yp = 0;
  153:     id_t id;
  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';
  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;
  195: 	return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
  196:     }
  197: #ifdef GID_NOBODY
  198:     /* Negative gids get mapped to nobody on Solaris. */
  199:     if (*cp == '-' && id != 0)
  200: 	grp->gr_gid = GID_NOBODY;
  201:     else
  202: #endif
  203: 	grp->gr_gid = (gid_t)id;
  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 */
  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) {
  321: 	if (grp->gr_gid == basegid || grp->gr_mem == NULL)
  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: }
  350: #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
  351: #endif /* HAVE_GETGROUPLIST */

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