File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / pwutil_impl.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 3 months 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) 1996, 1998-2005, 2007-2013
    3:  *	Todd C. Miller <Todd.Miller@courtesan.com>
    4:  *
    5:  * Permission to use, copy, modify, and distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  *
   17:  * Sponsored in part by the Defense Advanced Research Projects
   18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   20:  */
   21: 
   22: #include <config.h>
   23: 
   24: #include <sys/types.h>
   25: #include <stdio.h>
   26: #ifdef STDC_HEADERS
   27: # include <stdlib.h>
   28: # include <stddef.h>
   29: #else
   30: # ifdef HAVE_STDLIB_H
   31: #  include <stdlib.h>
   32: # endif
   33: #endif /* STDC_HEADERS */
   34: #ifdef HAVE_STRING_H
   35: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
   36: #  include <memory.h>
   37: # endif
   38: # include <string.h>
   39: #endif /* HAVE_STRING_H */
   40: #ifdef HAVE_STRINGS_H
   41: # include <strings.h>
   42: #endif /* HAVE_STRINGS_H */
   43: #ifdef HAVE_UNISTD_H
   44: # include <unistd.h>
   45: #endif /* HAVE_UNISTD_H */
   46: #include <limits.h>
   47: #include <pwd.h>
   48: #include <grp.h>
   49: 
   50: #include "sudoers.h"
   51: #include "pwutil.h"
   52: 
   53: #ifndef LOGIN_NAME_MAX
   54: # ifdef _POSIX_LOGIN_NAME_MAX
   55: #  define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
   56: # else
   57: #  define LOGIN_NAME_MAX 9
   58: # endif
   59: #endif /* LOGIN_NAME_MAX */
   60: 
   61: #define FIELD_SIZE(src, name, size)			\
   62: do {							\
   63: 	if (src->name) {				\
   64: 		size = strlen(src->name) + 1;		\
   65: 		total += size;				\
   66: 	}                                               \
   67: } while (0)
   68: 
   69: #define FIELD_COPY(src, dst, name, size)		\
   70: do {							\
   71: 	if (src->name) {				\
   72: 		memcpy(cp, src->name, size);		\
   73: 		dst->name = cp;				\
   74: 		cp += size;				\
   75: 	}						\
   76: } while (0)
   77: 
   78: /*
   79:  * Dynamically allocate space for a struct item plus the key and data
   80:  * elements.  If name is non-NULL it is used as the key, else the
   81:  * uid is the key.  Fills in datum from struct password.
   82:  */
   83: struct cache_item *
   84: sudo_make_pwitem(uid_t uid, const char *name)
   85: {
   86:     char *cp;
   87:     const char *pw_shell;
   88:     size_t nsize, psize, csize, gsize, dsize, ssize, total;
   89:     struct cache_item_pw *pwitem;
   90:     struct passwd *pw, *newpw;
   91:     debug_decl(sudo_make_pwitem, SUDO_DEBUG_NSS)
   92: 
   93:     /* Look up by name or uid. */
   94:     pw = name ? getpwnam(name) : getpwuid(uid);
   95:     if (pw == NULL)
   96: 	debug_return_ptr(NULL);
   97: 
   98:     /* If shell field is empty, expand to _PATH_BSHELL. */
   99:     pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
  100: 	? _PATH_BSHELL : pw->pw_shell;
  101: 
  102:     /* Allocate in one big chunk for easy freeing. */
  103:     nsize = psize = csize = gsize = dsize = ssize = 0;
  104:     total = sizeof(*pwitem);
  105:     FIELD_SIZE(pw, pw_name, nsize);
  106:     FIELD_SIZE(pw, pw_passwd, psize);
  107: #ifdef HAVE_LOGIN_CAP_H
  108:     FIELD_SIZE(pw, pw_class, csize);
  109: #endif
  110:     FIELD_SIZE(pw, pw_gecos, gsize);
  111:     FIELD_SIZE(pw, pw_dir, dsize);
  112:     /* Treat shell specially since we expand "" -> _PATH_BSHELL */
  113:     ssize = strlen(pw_shell) + 1;
  114:     total += ssize;
  115:     if (name != NULL)
  116: 	total += strlen(name) + 1;
  117: 
  118:     /* Allocate space for struct item, struct passwd and the strings. */
  119:     pwitem = ecalloc(1, total);
  120:     newpw = &pwitem->pw;
  121: 
  122:     /*
  123:      * Copy in passwd contents and make strings relative to space
  124:      * at the end of the struct.
  125:      */
  126:     memcpy(newpw, pw, sizeof(*pw));
  127:     cp = (char *)(pwitem + 1);
  128:     FIELD_COPY(pw, newpw, pw_name, nsize);
  129:     FIELD_COPY(pw, newpw, pw_passwd, psize);
  130: #ifdef HAVE_LOGIN_CAP_H
  131:     FIELD_COPY(pw, newpw, pw_class, csize);
  132: #endif
  133:     FIELD_COPY(pw, newpw, pw_gecos, gsize);
  134:     FIELD_COPY(pw, newpw, pw_dir, dsize);
  135:     /* Treat shell specially since we expand "" -> _PATH_BSHELL */
  136:     memcpy(cp, pw_shell, ssize);
  137:     newpw->pw_shell = cp;
  138:     cp += ssize;
  139: 
  140:     /* Set key and datum. */
  141:     if (name != NULL) {
  142: 	memcpy(cp, name, strlen(name) + 1);
  143: 	pwitem->cache.k.name = cp;
  144:     } else {
  145: 	pwitem->cache.k.uid = pw->pw_uid;
  146:     }
  147:     pwitem->cache.d.pw = newpw;
  148:     pwitem->cache.refcnt = 1;
  149: 
  150:     debug_return_ptr(&pwitem->cache);
  151: }
  152: 
  153: /*
  154:  * Dynamically allocate space for a struct item plus the key and data
  155:  * elements.  If name is non-NULL it is used as the key, else the
  156:  * gid is the key.  Fills in datum from struct group.
  157:  */
  158: struct cache_item *
  159: sudo_make_gritem(gid_t gid, const char *name)
  160: {
  161:     char *cp;
  162:     size_t nsize, psize, nmem, total, len;
  163:     struct cache_item_gr *gritem;
  164:     struct group *gr, *newgr;
  165:     debug_decl(sudo_make_gritem, SUDO_DEBUG_NSS)
  166: 
  167:     /* Look up by name or gid. */
  168:     gr = name ? getgrnam(name) : getgrgid(gid);
  169:     if (gr == NULL)
  170: 	debug_return_ptr(NULL);
  171: 
  172:     /* Allocate in one big chunk for easy freeing. */
  173:     nsize = psize = nmem = 0;
  174:     total = sizeof(*gritem);
  175:     FIELD_SIZE(gr, gr_name, nsize);
  176:     FIELD_SIZE(gr, gr_passwd, psize);
  177:     if (gr->gr_mem) {
  178: 	for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)
  179: 	    total += strlen(gr->gr_mem[nmem]) + 1;
  180: 	nmem++;
  181: 	total += sizeof(char *) * nmem;
  182:     }
  183:     if (name != NULL)
  184: 	total += strlen(name) + 1;
  185: 
  186:     gritem = ecalloc(1, total);
  187: 
  188:     /*
  189:      * Copy in group contents and make strings relative to space
  190:      * at the end of the buffer.  Note that gr_mem must come
  191:      * immediately after struct group to guarantee proper alignment.
  192:      */
  193:     newgr = &gritem->gr;
  194:     memcpy(newgr, gr, sizeof(*gr));
  195:     cp = (char *)(gritem + 1);
  196:     if (gr->gr_mem) {
  197: 	newgr->gr_mem = (char **)cp;
  198: 	cp += sizeof(char *) * nmem;
  199: 	for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) {
  200: 	    len = strlen(gr->gr_mem[nmem]) + 1;
  201: 	    memcpy(cp, gr->gr_mem[nmem], len);
  202: 	    newgr->gr_mem[nmem] = cp;
  203: 	    cp += len;
  204: 	}
  205: 	newgr->gr_mem[nmem] = NULL;
  206:     }
  207:     FIELD_COPY(gr, newgr, gr_passwd, psize);
  208:     FIELD_COPY(gr, newgr, gr_name, nsize);
  209: 
  210:     /* Set key and datum. */
  211:     if (name != NULL) {
  212: 	memcpy(cp, name, strlen(name) + 1);
  213: 	gritem->cache.k.name = cp;
  214:     } else {
  215: 	gritem->cache.k.gid = gr->gr_gid;
  216:     }
  217:     gritem->cache.d.gr = newgr;
  218:     gritem->cache.refcnt = 1;
  219: 
  220:     debug_return_ptr(&gritem->cache);
  221: }
  222: 
  223: /*
  224:  * Dynamically allocate space for a struct item plus the key and data
  225:  * elements.  Fills in datum from user_gids or from getgrouplist(3).
  226:  */
  227: struct cache_item *
  228: sudo_make_grlist_item(const struct passwd *pw, char * const *unused1,
  229:     char * const *unused2)
  230: {
  231:     char *cp;
  232:     size_t nsize, ngroups, total, len;
  233:     struct cache_item_grlist *grlitem;
  234:     struct group_list *grlist;
  235:     GETGROUPS_T *gids;
  236:     struct group *grp;
  237:     int i, ngids, groupname_len;
  238:     debug_decl(sudo_make_grlist_item, SUDO_DEBUG_NSS)
  239: 
  240:     if (pw == sudo_user.pw && sudo_user.gids != NULL) {
  241: 	gids = user_gids;
  242: 	ngids = user_ngids;
  243: 	user_gids = NULL;
  244: 	user_ngids = 0;
  245:     } else {
  246: 	if (sudo_user.max_groups > 0) {
  247: 	    ngids = sudo_user.max_groups;
  248: 	    gids = emalloc2(ngids, sizeof(GETGROUPS_T));
  249: 	    (void)getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids);
  250: 	} else {
  251: #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
  252: 	    ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
  253: 	    if (ngids < 0)
  254: #endif
  255: 		ngids = NGROUPS_MAX * 2;
  256: 	    gids = emalloc2(ngids, sizeof(GETGROUPS_T));
  257: 	    if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {
  258: 		efree(gids);
  259: 		gids = emalloc2(ngids, sizeof(GETGROUPS_T));
  260: 		if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1)
  261: 		    ngids = -1;
  262: 	    }
  263: 	}
  264:     }
  265:     if (ngids <= 0) {
  266: 	efree(gids);
  267: 	debug_return_ptr(NULL);
  268:     }
  269: 
  270: #ifdef HAVE_SETAUTHDB
  271:     aix_setauthdb((char *) pw->pw_name);
  272: #endif
  273: 
  274: #if defined(HAVE_SYSCONF) && defined(_SC_LOGIN_NAME_MAX)
  275:     groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32);
  276: #else
  277:     groupname_len = MAX(LOGIN_NAME_MAX, 32);
  278: #endif
  279: 
  280:     /* Allocate in one big chunk for easy freeing. */
  281:     nsize = strlen(pw->pw_name) + 1;
  282:     total = sizeof(*grlitem) + nsize;
  283:     total += sizeof(char *) * ngids;
  284:     total += sizeof(gid_t *) * ngids;
  285:     total += groupname_len * ngids;
  286: 
  287: again:
  288:     grlitem = ecalloc(1, total);
  289: 
  290:     /*
  291:      * Copy in group list and make pointers relative to space
  292:      * at the end of the buffer.  Note that the groups array must come
  293:      * immediately after struct group to guarantee proper alignment.
  294:      */
  295:     grlist = &grlitem->grlist;
  296:     cp = (char *)(grlitem + 1);
  297:     grlist->groups = (char **)cp;
  298:     cp += sizeof(char *) * ngids;
  299:     grlist->gids = (gid_t *)cp;
  300:     cp += sizeof(gid_t) * ngids;
  301: 
  302:     /* Set key and datum. */
  303:     memcpy(cp, pw->pw_name, nsize);
  304:     grlitem->cache.k.name = cp;
  305:     grlitem->cache.d.grlist = grlist;
  306:     grlitem->cache.refcnt = 1;
  307:     cp += nsize;
  308: 
  309:     /*
  310:      * Store group IDs.
  311:      */
  312:     for (i = 0; i < ngids; i++)
  313: 	grlist->gids[i] = gids[i];
  314:     grlist->ngids = ngids;
  315: 
  316:     /*
  317:      * Resolve and store group names by ID.
  318:      */
  319:     ngroups = 0;
  320:     for (i = 0; i < ngids; i++) {
  321: 	if ((grp = sudo_getgrgid(gids[i])) != NULL) {
  322: 	    len = strlen(grp->gr_name) + 1;
  323: 	    if (cp - (char *)grlitem + len > total) {
  324: 		total += len + groupname_len;
  325: 		efree(grlitem);
  326: 		sudo_gr_delref(grp);
  327: 		goto again;
  328: 	    }
  329: 	    memcpy(cp, grp->gr_name, len);
  330: 	    grlist->groups[ngroups++] = cp;
  331: 	    cp += len;
  332: 	    sudo_gr_delref(grp);
  333: 	}
  334:     }
  335:     grlist->ngroups = ngroups;
  336:     efree(gids);
  337: 
  338: #ifdef HAVE_SETAUTHDB
  339:     aix_restoreauthdb();
  340: #endif
  341: 
  342:     debug_return_ptr(&grlitem->cache);
  343: }

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