Annotation of embedaddon/sudo/plugins/sudoers/pwutil_impl.c, revision 1.1
1.1 ! misho 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(struct passwd *pw, char * const *unused1,
! 229: char * const *unused2)
! 230: {
! 231: char *cp;
! 232: size_t i, 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 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 != -1) {
! 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>