2 * Copyright (c) 1996, 1998-2005, 2007-2011
3 * Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
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.
24 #include <sys/types.h>
26 #include <sys/param.h>
35 #endif /* STDC_HEADERS */
37 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
41 #endif /* HAVE_STRING_H */
44 #endif /* HAVE_STRINGS_H */
47 #endif /* HAVE_UNISTD_H */
50 #endif /* HAVE_SETAUTHDB */
58 * The passwd and group caches.
60 static struct rbtree *pwcache_byuid, *pwcache_byname;
61 static struct rbtree *grcache_bygid, *grcache_byname;
63 static int cmp_pwuid __P((const void *, const void *));
64 static int cmp_pwnam __P((const void *, const void *));
65 static int cmp_grgid __P((const void *, const void *));
67 #define cmp_grnam cmp_pwnam
69 #define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item)))
94 const struct cache_item *ci1 = (const struct cache_item *) v1;
95 const struct cache_item *ci2 = (const struct cache_item *) v2;
96 return ci1->k.uid - ci2->k.uid;
100 * Compare by user name.
107 const struct cache_item *ci1 = (const struct cache_item *) v1;
108 const struct cache_item *ci2 = (const struct cache_item *) v2;
109 return strcmp(ci1->k.name, ci2->k.name);
112 #define FIELD_SIZE(src, name, size) \
115 size = strlen(src->name) + 1; \
120 #define FIELD_COPY(src, dst, name, size) \
123 memcpy(cp, src->name, size); \
130 * Dynamically allocate space for a struct item plus the key and data
131 * elements. If name is non-NULL it is used as the key, else the
132 * uid is the key. Fills in datum from struct password.
134 * We would like to fill in the encrypted password too but the
135 * call to the shadow function could overwrite the pw buffer (NIS).
137 static struct cache_item *
138 make_pwitem(pw, name)
139 const struct passwd *pw;
143 const char *pw_shell;
144 size_t nsize, psize, csize, gsize, dsize, ssize, total;
145 struct cache_item *item;
146 struct passwd *newpw;
148 /* If shell field is empty, expand to _PATH_BSHELL. */
149 pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
150 ? _PATH_BSHELL : pw->pw_shell;
152 /* Allocate in one big chunk for easy freeing. */
153 nsize = psize = csize = gsize = dsize = ssize = 0;
154 total = sizeof(struct cache_item) + sizeof(struct passwd);
155 FIELD_SIZE(pw, pw_name, nsize);
156 FIELD_SIZE(pw, pw_passwd, psize);
157 #ifdef HAVE_LOGIN_CAP_H
158 FIELD_SIZE(pw, pw_class, csize);
160 FIELD_SIZE(pw, pw_gecos, gsize);
161 FIELD_SIZE(pw, pw_dir, dsize);
162 /* Treat shell specially since we expand "" -> _PATH_BSHELL */
163 ssize = strlen(pw_shell) + 1;
166 total += strlen(name) + 1;
168 /* Allocate space for struct item, struct passwd and the strings. */
169 if ((item = malloc(total)) == NULL)
171 cp = (char *) item + sizeof(struct cache_item);
174 * Copy in passwd contents and make strings relative to space
175 * at the end of the buffer.
177 newpw = (struct passwd *) cp;
178 memcpy(newpw, pw, sizeof(struct passwd));
179 cp += sizeof(struct passwd);
180 FIELD_COPY(pw, newpw, pw_name, nsize);
181 FIELD_COPY(pw, newpw, pw_passwd, psize);
182 #ifdef HAVE_LOGIN_CAP_H
183 FIELD_COPY(pw, newpw, pw_class, csize);
185 FIELD_COPY(pw, newpw, pw_gecos, gsize);
186 FIELD_COPY(pw, newpw, pw_dir, dsize);
187 /* Treat shell specially since we expand "" -> _PATH_BSHELL */
188 memcpy(cp, pw_shell, ssize);
189 newpw->pw_shell = cp;
192 /* Set key and datum. */
194 memcpy(cp, name, strlen(name) + 1);
197 item->k.uid = pw->pw_uid;
209 ptr_to_item(pw)->refcnt++;
216 struct cache_item *item = v;
218 if (--item->refcnt == 0)
226 pw_delref_item(ptr_to_item(pw));
230 * Get a password entry by uid and allocate space for it.
231 * Fills in pw_passwd from shadow file if necessary.
237 struct cache_item key, *item;
241 if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
242 item = (struct cache_item *) node->data;
246 * Cache passwd db entry if it exists or a negative response if not.
248 #ifdef HAVE_SETAUTHDB
249 aix_setauthdb(IDtouser(uid));
251 if ((key.d.pw = getpwuid(uid)) != NULL) {
252 item = make_pwitem(key.d.pw, NULL);
253 if (rbinsert(pwcache_byuid, item) != NULL)
254 errorx(1, "unable to cache uid %u (%s), already exists",
255 (unsigned int) uid, item->d.pw->pw_name);
257 item = emalloc(sizeof(*item));
261 if (rbinsert(pwcache_byuid, item) != NULL)
262 errorx(1, "unable to cache uid %u, already exists",
265 #ifdef HAVE_SETAUTHDB
274 * Get a password entry by name and allocate space for it.
275 * Fills in pw_passwd from shadow file if necessary.
281 struct cache_item key, *item;
285 key.k.name = (char *) name;
286 if ((node = rbfind(pwcache_byname, &key)) != NULL) {
287 item = (struct cache_item *) node->data;
291 * Cache passwd db entry if it exists or a negative response if not.
293 #ifdef HAVE_SETAUTHDB
294 aix_setauthdb((char *) name);
296 if ((key.d.pw = getpwnam(name)) != NULL) {
297 item = make_pwitem(key.d.pw, name);
298 if (rbinsert(pwcache_byname, item) != NULL)
299 errorx(1, "unable to cache user %s, already exists", name);
301 len = strlen(name) + 1;
302 item = emalloc(sizeof(*item) + len);
304 item->k.name = (char *) item + sizeof(*item);
305 memcpy(item->k.name, name, len);
307 if (rbinsert(pwcache_byname, item) != NULL)
308 errorx(1, "unable to cache user %s, already exists", name);
310 #ifdef HAVE_SETAUTHDB
319 * Take a uid in string form "#123" and return a faked up passwd struct.
322 sudo_fakepwnam(user, gid)
326 struct cache_item *item;
332 namelen = strlen(user);
333 len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
334 sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
335 sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
337 for (i = 0; i < 2; i++) {
339 zero_bytes(item, sizeof(*item) + sizeof(*pw));
340 pw = (struct passwd *) ((char *)item + sizeof(*item));
341 pw->pw_uid = (uid_t) atoi(user + 1);
343 pw->pw_name = (char *)pw + sizeof(struct passwd);
344 memcpy(pw->pw_name, user, namelen + 1);
345 pw->pw_passwd = pw->pw_name + namelen + 1;
346 memcpy(pw->pw_passwd, "*", 2);
347 pw->pw_gecos = pw->pw_passwd + 2;
348 pw->pw_gecos[0] = '\0';
349 pw->pw_dir = pw->pw_gecos + 1;
350 memcpy(pw->pw_dir, "/", 2);
351 pw->pw_shell = pw->pw_dir + 2;
352 memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
357 /* Store by uid, overwriting cached version. */
358 item->k.uid = pw->pw_uid;
359 if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
360 pw_delref_item(node->data);
364 /* Store by name, overwriting cached version. */
365 item->k.name = pw->pw_name;
366 if ((node = rbinsert(pwcache_byname, item)) != NULL) {
367 pw_delref_item(node->data);
380 if (pwcache_byuid == NULL)
381 pwcache_byuid = rbcreate(cmp_pwuid);
382 if (pwcache_byname == NULL)
383 pwcache_byname = rbcreate(cmp_pwnam);
389 if (pwcache_byuid != NULL) {
390 rbdestroy(pwcache_byuid, pw_delref_item);
391 pwcache_byuid = NULL;
393 if (pwcache_byname != NULL) {
394 rbdestroy(pwcache_byname, pw_delref_item);
395 pwcache_byname = NULL;
414 const struct cache_item *ci1 = (const struct cache_item *) v1;
415 const struct cache_item *ci2 = (const struct cache_item *) v2;
416 return ci1->k.gid - ci2->k.gid;
420 * Dynamically allocate space for a struct item plus the key and data
421 * elements. If name is non-NULL it is used as the key, else the
422 * gid is the key. Fills in datum from struct group.
424 static struct cache_item *
425 make_gritem(gr, name)
426 const struct group *gr;
430 size_t nsize, psize, nmem, total, len;
431 struct cache_item *item;
434 /* Allocate in one big chunk for easy freeing. */
435 nsize = psize = nmem = 0;
436 total = sizeof(struct cache_item) + sizeof(struct group);
437 FIELD_SIZE(gr, gr_name, nsize);
438 FIELD_SIZE(gr, gr_passwd, psize);
440 for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)
441 total += strlen(gr->gr_mem[nmem]) + 1;
443 total += sizeof(char *) * nmem;
446 total += strlen(name) + 1;
448 if ((item = malloc(total)) == NULL)
450 cp = (char *) item + sizeof(struct cache_item);
453 * Copy in group contents and make strings relative to space
454 * at the end of the buffer. Note that gr_mem must come
455 * immediately after struct group to guarantee proper alignment.
457 newgr = (struct group *)cp;
458 memcpy(newgr, gr, sizeof(struct group));
459 cp += sizeof(struct group);
461 newgr->gr_mem = (char **)cp;
462 cp += sizeof(char *) * nmem;
463 for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) {
464 len = strlen(gr->gr_mem[nmem]) + 1;
465 memcpy(cp, gr->gr_mem[nmem], len);
466 newgr->gr_mem[nmem] = cp;
469 newgr->gr_mem[nmem] = NULL;
471 FIELD_COPY(gr, newgr, gr_passwd, psize);
472 FIELD_COPY(gr, newgr, gr_name, nsize);
474 /* Set key and datum. */
476 memcpy(cp, name, strlen(name) + 1);
479 item->k.gid = gr->gr_gid;
491 ptr_to_item(gr)->refcnt++;
498 struct cache_item *item = v;
500 if (--item->refcnt == 0)
508 gr_delref_item(ptr_to_item(gr));
512 * Get a group entry by gid and allocate space for it.
518 struct cache_item key, *item;
522 if ((node = rbfind(grcache_bygid, &key)) != NULL) {
523 item = (struct cache_item *) node->data;
527 * Cache group db entry if it exists or a negative response if not.
529 if ((key.d.gr = getgrgid(gid)) != NULL) {
530 item = make_gritem(key.d.gr, NULL);
531 if (rbinsert(grcache_bygid, item) != NULL)
532 errorx(1, "unable to cache gid %u (%s), already exists",
533 (unsigned int) gid, key.d.gr->gr_name);
535 item = emalloc(sizeof(*item));
539 if (rbinsert(grcache_bygid, item) != NULL)
540 errorx(1, "unable to cache gid %u, already exists",
549 * Get a group entry by name and allocate space for it.
555 struct cache_item key, *item;
559 key.k.name = (char *) name;
560 if ((node = rbfind(grcache_byname, &key)) != NULL) {
561 item = (struct cache_item *) node->data;
565 * Cache group db entry if it exists or a negative response if not.
567 if ((key.d.gr = getgrnam(name)) != NULL) {
568 item = make_gritem(key.d.gr, name);
569 if (rbinsert(grcache_byname, item) != NULL)
570 errorx(1, "unable to cache group %s, already exists", name);
572 len = strlen(name) + 1;
573 item = emalloc(sizeof(*item) + len);
575 item->k.name = (char *) item + sizeof(*item);
576 memcpy(item->k.name, name, len);
578 if (rbinsert(grcache_byname, item) != NULL)
579 errorx(1, "unable to cache group %s, already exists", name);
587 * Take a gid in string form "#123" and return a faked up group struct.
590 sudo_fakegrnam(group)
593 struct cache_item *item;
599 namelen = strlen(group);
600 len = sizeof(*item) + sizeof(*gr) + namelen + 1;
602 for (i = 0; i < 2; i++) {
604 zero_bytes(item, sizeof(*item) + sizeof(*gr));
605 gr = (struct group *) ((char *)item + sizeof(*item));
606 gr->gr_gid = (gid_t) atoi(group + 1);
607 gr->gr_name = (char *)gr + sizeof(struct group);
608 memcpy(gr->gr_name, group, namelen + 1);
613 /* Store by gid, overwriting cached version. */
614 item->k.gid = gr->gr_gid;
615 if ((node = rbinsert(grcache_bygid, item)) != NULL) {
616 gr_delref_item(node->data);
620 /* Store by name, overwriting cached version. */
621 item->k.name = gr->gr_name;
622 if ((node = rbinsert(grcache_byname, item)) != NULL) {
623 gr_delref_item(node->data);
636 if (grcache_bygid == NULL)
637 grcache_bygid = rbcreate(cmp_grgid);
638 if (grcache_byname == NULL)
639 grcache_byname = rbcreate(cmp_grnam);
645 if (grcache_bygid != NULL) {
646 rbdestroy(grcache_bygid, gr_delref_item);
647 grcache_bygid = NULL;
649 if (grcache_byname != NULL) {
650 rbdestroy(grcache_byname, gr_delref_item);
651 grcache_byname = NULL;
663 user_in_group(pw, group)
667 #ifdef HAVE_MBR_CHECK_MEMBERSHIP
677 #ifdef HAVE_SETAUTHDB
678 aix_setauthdb(pw->pw_name);
680 /* A group name that begins with a '#' may be a gid. */
681 if ((grp = sudo_getgrnam(group)) == NULL && *group == '#')
682 grp = sudo_getgrgid(atoi(group + 1));
683 #ifdef HAVE_SETAUTHDB
689 /* check against user's primary (passwd file) gid */
690 if (grp->gr_gid == pw->pw_gid) {
695 #ifdef HAVE_MBR_CHECK_MEMBERSHIP
696 /* If we are matching the invoking user use the stashed uuid. */
697 if (strcmp(pw->pw_name, user_name) == 0) {
698 if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
699 mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) {
704 if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 &&
705 mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
706 mbr_check_membership(uu, gu, &ismember) == 0 && ismember) {
711 #else /* HAVE_MBR_CHECK_MEMBERSHIP */
712 # ifdef HAVE_GETGROUPS
714 * If we are matching the invoking or list user and that user has a
715 * supplementary group vector, check it.
717 if (user_ngroups > 0 &&
718 strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
719 for (i = 0; i < user_ngroups; i++) {
720 if (grp->gr_gid == user_groups[i]) {
726 # endif /* HAVE_GETGROUPS */
728 if (grp != NULL && grp->gr_mem != NULL) {
729 for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
730 if (strcmp(*gr_mem, pw->pw_name) == 0) {
737 #endif /* HAVE_MBR_CHECK_MEMBERSHIP */