File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / getgrouplist.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:11 2013 UTC (11 years ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_7p0, v1_8_7, HEAD
1.8.7

    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 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 */
  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: }
  314: #endif /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */
  315: #endif /* HAVE_GETGROUPLIST */

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