Return to pwutil_impl.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
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: }