--- embedaddon/sudo/plugins/sudoers/pwutil.c 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/plugins/sudoers/pwutil.c 2012/05/29 12:26:49 1.1.1.2 @@ -73,8 +73,11 @@ static int cmp_grgid(const void *, const void *); #define cmp_grnam cmp_pwnam -#define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item))) +#define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p))) +/* + * Generic cache element. + */ struct cache_item { unsigned int refcnt; /* key */ @@ -92,6 +95,26 @@ struct cache_item { }; /* + * Container structs to simpify size and offset calculations and guarantee + * proper aligment of struct passwd, group and group_list. + */ +struct cache_item_pw { + struct cache_item cache; + struct passwd pw; +}; + +struct cache_item_gr { + struct cache_item cache; + struct group gr; +}; + +struct cache_item_grlist { + struct cache_item cache; + struct group_list grlist; + /* actually bigger */ +}; + +/* * Compare by uid. */ static int @@ -134,9 +157,6 @@ do { \ * Dynamically allocate space for a struct item plus the key and data * elements. If name is non-NULL it is used as the key, else the * uid is the key. Fills in datum from struct password. - * - * We would like to fill in the encrypted password too but the - * call to the shadow function could overwrite the pw buffer (NIS). */ static struct cache_item * make_pwitem(const struct passwd *pw, const char *name) @@ -144,8 +164,9 @@ make_pwitem(const struct passwd *pw, const char *name) char *cp; const char *pw_shell; size_t nsize, psize, csize, gsize, dsize, ssize, total; - struct cache_item *item; + struct cache_item_pw *pwitem; struct passwd *newpw; + debug_decl(make_pwitem, SUDO_DEBUG_NSS) /* If shell field is empty, expand to _PATH_BSHELL. */ pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') @@ -153,7 +174,7 @@ make_pwitem(const struct passwd *pw, const char *name) /* Allocate in one big chunk for easy freeing. */ nsize = psize = csize = gsize = dsize = ssize = 0; - total = sizeof(struct cache_item) + sizeof(struct passwd); + total = sizeof(*pwitem); FIELD_SIZE(pw, pw_name, nsize); FIELD_SIZE(pw, pw_passwd, psize); #ifdef HAVE_LOGIN_CAP_H @@ -168,16 +189,15 @@ make_pwitem(const struct passwd *pw, const char *name) total += strlen(name) + 1; /* Allocate space for struct item, struct passwd and the strings. */ - item = emalloc(total); - cp = (char *) item + sizeof(struct cache_item); + pwitem = ecalloc(1, total); + newpw = &pwitem->pw; /* * Copy in passwd contents and make strings relative to space - * at the end of the buffer. + * at the end of the struct. */ - newpw = (struct passwd *) cp; - memcpy(newpw, pw, sizeof(struct passwd)); - cp += sizeof(struct passwd); + memcpy(newpw, pw, sizeof(*pw)); + cp = (char *)(pwitem + 1); FIELD_COPY(pw, newpw, pw_name, nsize); FIELD_COPY(pw, newpw, pw_passwd, psize); #ifdef HAVE_LOGIN_CAP_H @@ -193,46 +213,53 @@ make_pwitem(const struct passwd *pw, const char *name) /* Set key and datum. */ if (name != NULL) { memcpy(cp, name, strlen(name) + 1); - item->k.name = cp; + pwitem->cache.k.name = cp; } else { - item->k.uid = pw->pw_uid; + pwitem->cache.k.uid = pw->pw_uid; } - item->d.pw = newpw; - item->refcnt = 1; + pwitem->cache.d.pw = newpw; + pwitem->cache.refcnt = 1; - return item; + debug_return_ptr(&pwitem->cache); } void pw_addref(struct passwd *pw) { + debug_decl(pw_addref, SUDO_DEBUG_NSS) ptr_to_item(pw)->refcnt++; + debug_return; } static void pw_delref_item(void *v) { struct cache_item *item = v; + debug_decl(pw_delref_item, SUDO_DEBUG_NSS) if (--item->refcnt == 0) efree(item); + + debug_return; } void pw_delref(struct passwd *pw) { + debug_decl(pw_delref, SUDO_DEBUG_NSS) pw_delref_item(ptr_to_item(pw)); + debug_return; } /* * Get a password entry by uid and allocate space for it. - * Fills in pw_passwd from shadow file if necessary. */ struct passwd * sudo_getpwuid(uid_t uid) { struct cache_item key, *item; struct rbnode *node; + debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS) key.k.uid = uid; if ((node = rbfind(pwcache_byuid, &key)) != NULL) { @@ -251,10 +278,10 @@ sudo_getpwuid(uid_t uid) errorx(1, _("unable to cache uid %u (%s), already exists"), (unsigned int) uid, item->d.pw->pw_name); } else { - item = emalloc(sizeof(*item)); + item = ecalloc(1, sizeof(*item)); item->refcnt = 1; item->k.uid = uid; - item->d.pw = NULL; + /* item->d.pw = NULL; */ if (rbinsert(pwcache_byuid, item) != NULL) errorx(1, _("unable to cache uid %u, already exists"), (unsigned int) uid); @@ -264,12 +291,11 @@ sudo_getpwuid(uid_t uid) #endif done: item->refcnt++; - return item->d.pw; + debug_return_ptr(item->d.pw); } /* * Get a password entry by name and allocate space for it. - * Fills in pw_passwd from shadow file if necessary. */ struct passwd * sudo_getpwnam(const char *name) @@ -277,6 +303,7 @@ sudo_getpwnam(const char *name) struct cache_item key, *item; struct rbnode *node; size_t len; + debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS) key.k.name = (char *) name; if ((node = rbfind(pwcache_byname, &key)) != NULL) { @@ -295,11 +322,11 @@ sudo_getpwnam(const char *name) errorx(1, _("unable to cache user %s, already exists"), name); } else { len = strlen(name) + 1; - item = emalloc(sizeof(*item) + len); + item = ecalloc(1, sizeof(*item) + len); item->refcnt = 1; item->k.name = (char *) item + sizeof(*item); memcpy(item->k.name, name, len); - item->d.pw = NULL; + /* item->d.pw = NULL; */ if (rbinsert(pwcache_byname, item) != NULL) errorx(1, _("unable to cache user %s, already exists"), name); } @@ -308,7 +335,7 @@ sudo_getpwnam(const char *name) #endif done: item->refcnt++; - return item->d.pw; + debug_return_ptr(item->d.pw); } /* @@ -317,24 +344,24 @@ done: struct passwd * sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid) { - struct cache_item *item; + struct cache_item_pw *pwitem; struct passwd *pw; struct rbnode *node; size_t len, namelen; int i; + debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS) namelen = strlen(user); - len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ + + len = sizeof(*pwitem) + namelen + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); for (i = 0; i < 2; i++) { - item = emalloc(len); - zero_bytes(item, sizeof(*item) + sizeof(*pw)); - pw = (struct passwd *) ((char *)item + sizeof(*item)); + pwitem = ecalloc(1, len); + pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; - pw->pw_name = (char *)pw + sizeof(struct passwd); + pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, namelen + 1); pw->pw_passwd = pw->pw_name + namelen + 1; memcpy(pw->pw_passwd, "*", 2); @@ -345,26 +372,26 @@ sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi pw->pw_shell = pw->pw_dir + 2; memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); - item->refcnt = 1; - item->d.pw = pw; + pwitem->cache.refcnt = 1; + pwitem->cache.d.pw = pw; if (i == 0) { /* Store by uid, overwriting cached version. */ - item->k.uid = pw->pw_uid; - if ((node = rbinsert(pwcache_byuid, item)) != NULL) { + pwitem->cache.k.uid = pw->pw_uid; + if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { pw_delref_item(node->data); - node->data = item; + node->data = &pwitem->cache; } } else { /* Store by name, overwriting cached version. */ - item->k.name = pw->pw_name; - if ((node = rbinsert(pwcache_byname, item)) != NULL) { + pwitem->cache.k.name = pw->pw_name; + if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { pw_delref_item(node->data); - node->data = item; + node->data = &pwitem->cache; } } } - item->refcnt++; - return pw; + pwitem->cache.refcnt++; + debug_return_ptr(pw); } /* @@ -382,16 +409,22 @@ sudo_fakepwnam(const char *user, gid_t gid) void sudo_setpwent(void) { + debug_decl(sudo_setpwent, SUDO_DEBUG_NSS) + setpwent(); if (pwcache_byuid == NULL) pwcache_byuid = rbcreate(cmp_pwuid); if (pwcache_byname == NULL) pwcache_byname = rbcreate(cmp_pwnam); + + debug_return; } void sudo_freepwcache(void) { + debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS) + if (pwcache_byuid != NULL) { rbdestroy(pwcache_byuid, pw_delref_item); pwcache_byuid = NULL; @@ -400,13 +433,19 @@ sudo_freepwcache(void) rbdestroy(pwcache_byname, pw_delref_item); pwcache_byname = NULL; } + + debug_return; } void sudo_endpwent(void) { + debug_decl(sudo_endpwent, SUDO_DEBUG_NSS) + endpwent(); sudo_freepwcache(); + + debug_return; } /* @@ -430,12 +469,13 @@ make_gritem(const struct group *gr, const char *name) { char *cp; size_t nsize, psize, nmem, total, len; - struct cache_item *item; + struct cache_item_gr *gritem; struct group *newgr; + debug_decl(make_gritem, SUDO_DEBUG_NSS) /* Allocate in one big chunk for easy freeing. */ nsize = psize = nmem = 0; - total = sizeof(struct cache_item) + sizeof(struct group); + total = sizeof(*gritem); FIELD_SIZE(gr, gr_name, nsize); FIELD_SIZE(gr, gr_passwd, psize); if (gr->gr_mem) { @@ -447,17 +487,16 @@ make_gritem(const struct group *gr, const char *name) if (name != NULL) total += strlen(name) + 1; - item = emalloc(total); - cp = (char *) item + sizeof(struct cache_item); + gritem = ecalloc(1, total); /* * Copy in group contents and make strings relative to space * at the end of the buffer. Note that gr_mem must come * immediately after struct group to guarantee proper alignment. */ - newgr = (struct group *)cp; - memcpy(newgr, gr, sizeof(struct group)); - cp += sizeof(struct group); + newgr = &gritem->gr; + memcpy(newgr, gr, sizeof(*gr)); + cp = (char *)(gritem + 1); if (gr->gr_mem) { newgr->gr_mem = (char **)cp; cp += sizeof(char *) * nmem; @@ -475,14 +514,14 @@ make_gritem(const struct group *gr, const char *name) /* Set key and datum. */ if (name != NULL) { memcpy(cp, name, strlen(name) + 1); - item->k.name = cp; + gritem->cache.k.name = cp; } else { - item->k.gid = gr->gr_gid; + gritem->cache.k.gid = gr->gr_gid; } - item->d.gr = newgr; - item->refcnt = 1; + gritem->cache.d.gr = newgr; + gritem->cache.refcnt = 1; - return item; + debug_return_ptr(&gritem->cache); } #ifdef HAVE_UTMPX_H @@ -504,9 +543,10 @@ make_grlist_item(const char *user, GETGROUPS_T *gids, { char *cp; size_t i, nsize, ngroups, total, len; - struct cache_item *item; + struct cache_item_grlist *grlitem; struct group_list *grlist; struct group *grp; + debug_decl(make_grlist_item, SUDO_DEBUG_NSS) #ifdef HAVE_SETAUTHDB aix_setauthdb((char *) user); @@ -514,23 +554,21 @@ make_grlist_item(const char *user, GETGROUPS_T *gids, /* Allocate in one big chunk for easy freeing. */ nsize = strlen(user) + 1; - total = sizeof(struct cache_item) + sizeof(struct group_list) + nsize; + total = sizeof(*grlitem) + nsize; total += sizeof(char *) * ngids; total += sizeof(gid_t *) * ngids; total += GROUPNAME_LEN * ngids; again: - item = emalloc(total); - cp = (char *) item + sizeof(struct cache_item); + grlitem = ecalloc(1, total); /* * Copy in group list and make pointers relative to space * at the end of the buffer. Note that the groups array must come * immediately after struct group to guarantee proper alignment. */ - grlist = (struct group_list *)cp; - zero_bytes(grlist, sizeof(struct group_list)); - cp += sizeof(struct group_list); + grlist = &grlitem->grlist; + cp = (char *)(grlitem + 1); grlist->groups = (char **)cp; cp += sizeof(char *) * ngids; grlist->gids = (gid_t *)cp; @@ -538,9 +576,9 @@ again: /* Set key and datum. */ memcpy(cp, user, nsize); - item->k.name = cp; - item->d.grlist = grlist; - item->refcnt = 1; + grlitem->cache.k.name = cp; + grlitem->cache.d.grlist = grlist; + grlitem->cache.refcnt = 1; cp += nsize; /* @@ -557,9 +595,9 @@ again: for (i = 0; i < ngids; i++) { if ((grp = sudo_getgrgid(gids[i])) != NULL) { len = strlen(grp->gr_name) + 1; - if (cp - (char *)item + len > total) { + if (cp - (char *)grlitem + len > total) { total += len + GROUPNAME_LEN; - efree(item); + efree(grlitem); gr_delref(grp); goto again; } @@ -575,28 +613,35 @@ again: aix_restoreauthdb(); #endif - return item; + debug_return_ptr(&grlitem->cache); } void gr_addref(struct group *gr) { + debug_decl(gr_addref, SUDO_DEBUG_NSS) ptr_to_item(gr)->refcnt++; + debug_return; } static void gr_delref_item(void *v) { struct cache_item *item = v; + debug_decl(gr_delref_item, SUDO_DEBUG_NSS) if (--item->refcnt == 0) efree(item); + + debug_return; } void gr_delref(struct group *gr) { + debug_decl(gr_delref, SUDO_DEBUG_NSS) gr_delref_item(ptr_to_item(gr)); + debug_return; } /* @@ -607,6 +652,7 @@ sudo_getgrgid(gid_t gid) { struct cache_item key, *item; struct rbnode *node; + debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS) key.k.gid = gid; if ((node = rbfind(grcache_bygid, &key)) != NULL) { @@ -622,17 +668,17 @@ sudo_getgrgid(gid_t gid) errorx(1, _("unable to cache gid %u (%s), already exists"), (unsigned int) gid, key.d.gr->gr_name); } else { - item = emalloc(sizeof(*item)); + item = ecalloc(1, sizeof(*item)); item->refcnt = 1; item->k.gid = gid; - item->d.gr = NULL; + /* item->d.gr = NULL; */ if (rbinsert(grcache_bygid, item) != NULL) errorx(1, _("unable to cache gid %u, already exists"), (unsigned int) gid); } done: item->refcnt++; - return item->d.gr; + debug_return_ptr(item->d.gr); } /* @@ -644,6 +690,7 @@ sudo_getgrnam(const char *name) struct cache_item key, *item; struct rbnode *node; size_t len; + debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS) key.k.name = (char *) name; if ((node = rbfind(grcache_byname, &key)) != NULL) { @@ -659,17 +706,17 @@ sudo_getgrnam(const char *name) errorx(1, _("unable to cache group %s, already exists"), name); } else { len = strlen(name) + 1; - item = emalloc(sizeof(*item) + len); + item = ecalloc(1, sizeof(*item) + len); item->refcnt = 1; item->k.name = (char *) item + sizeof(*item); memcpy(item->k.name, name, len); - item->d.gr = NULL; + /* item->d.gr = NULL; */ if (rbinsert(grcache_byname, item) != NULL) errorx(1, _("unable to cache group %s, already exists"), name); } done: item->refcnt++; - return item->d.gr; + debug_return_ptr(item->d.gr); } /* @@ -678,69 +725,78 @@ done: struct group * sudo_fakegrnam(const char *group) { - struct cache_item *item; + struct cache_item_gr *gritem; struct group *gr; struct rbnode *node; size_t len, namelen; int i; + debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS) namelen = strlen(group); - len = sizeof(*item) + sizeof(*gr) + namelen + 1; + len = sizeof(*gritem) + namelen + 1; for (i = 0; i < 2; i++) { - item = emalloc(len); - zero_bytes(item, sizeof(*item) + sizeof(*gr)); - gr = (struct group *) ((char *)item + sizeof(*item)); + gritem = ecalloc(1, len); + gr = &gritem->gr; gr->gr_gid = (gid_t) atoi(group + 1); - gr->gr_name = (char *)gr + sizeof(struct group); + gr->gr_name = (char *)(gritem + 1); memcpy(gr->gr_name, group, namelen + 1); - item->refcnt = 1; - item->d.gr = gr; + gritem->cache.refcnt = 1; + gritem->cache.d.gr = gr; if (i == 0) { /* Store by gid, overwriting cached version. */ - item->k.gid = gr->gr_gid; - if ((node = rbinsert(grcache_bygid, item)) != NULL) { + gritem->cache.k.gid = gr->gr_gid; + if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) { gr_delref_item(node->data); - node->data = item; + node->data = &gritem->cache; } } else { /* Store by name, overwriting cached version. */ - item->k.name = gr->gr_name; - if ((node = rbinsert(grcache_byname, item)) != NULL) { + gritem->cache.k.name = gr->gr_name; + if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) { gr_delref_item(node->data); - node->data = item; + node->data = &gritem->cache; } } } - item->refcnt++; - return gr; + gritem->cache.refcnt++; + debug_return_ptr(gr); } void grlist_addref(struct group_list *grlist) { + debug_decl(gr_addref, SUDO_DEBUG_NSS) ptr_to_item(grlist)->refcnt++; + debug_return; } static void grlist_delref_item(void *v) { struct cache_item *item = v; + debug_decl(gr_delref_item, SUDO_DEBUG_NSS) if (--item->refcnt == 0) efree(item); + + debug_return; } void grlist_delref(struct group_list *grlist) { + debug_decl(gr_delref, SUDO_DEBUG_NSS) grlist_delref_item(ptr_to_item(grlist)); + debug_return; } void sudo_setgrent(void) { + debug_decl(sudo_setgrent, SUDO_DEBUG_NSS) + setgrent(); if (grcache_bygid == NULL) grcache_bygid = rbcreate(cmp_grgid); @@ -748,11 +804,15 @@ sudo_setgrent(void) grcache_byname = rbcreate(cmp_grnam); if (grlist_cache == NULL) grlist_cache = rbcreate(cmp_grnam); + + debug_return; } void sudo_freegrcache(void) { + debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS) + if (grcache_bygid != NULL) { rbdestroy(grcache_bygid, gr_delref_item); grcache_bygid = NULL; @@ -765,13 +825,19 @@ sudo_freegrcache(void) rbdestroy(grlist_cache, grlist_delref_item); grlist_cache = NULL; } + + debug_return; } void sudo_endgrent(void) { + debug_decl(sudo_endgrent, SUDO_DEBUG_NSS) + endgrent(); sudo_freegrcache(); + + debug_return; } struct group_list * @@ -782,6 +848,7 @@ get_group_list(struct passwd *pw) size_t len; GETGROUPS_T *gids; int ngids; + debug_decl(get_group_list, SUDO_DEBUG_NSS) key.k.name = pw->pw_name; if ((node = rbfind(grlist_cache, &key)) != NULL) { @@ -802,7 +869,7 @@ get_group_list(struct passwd *pw) gids = emalloc2(ngids, sizeof(GETGROUPS_T)); if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { efree(gids); - return NULL; + debug_return_ptr(NULL); } } if (ngids > 0) { @@ -815,18 +882,18 @@ get_group_list(struct passwd *pw) } else { /* Should not happen. */ len = strlen(pw->pw_name) + 1; - item = emalloc(sizeof(*item) + len); + item = ecalloc(1, sizeof(*item) + len); item->refcnt = 1; item->k.name = (char *) item + sizeof(*item); memcpy(item->k.name, pw->pw_name, len); - item->d.grlist = NULL; + /* item->d.grlist = NULL; */ if (rbinsert(grlist_cache, item) != NULL) errorx(1, "unable to cache group list for %s, already exists", pw->pw_name); } done: item->refcnt++; - return item->d.grlist; + debug_return_ptr(item->d.grlist); } void @@ -834,6 +901,7 @@ set_group_list(const char *user, GETGROUPS_T *gids, in { struct cache_item key, *item; struct rbnode *node; + debug_decl(set_group_list, SUDO_DEBUG_NSS) /* * Cache group db entry if it doesn't already exist @@ -846,14 +914,17 @@ set_group_list(const char *user, GETGROUPS_T *gids, in errorx(1, "unable to cache group list for %s, already exists", user); } + debug_return; } -int +bool user_in_group(struct passwd *pw, const char *group) { struct group_list *grlist; struct group *grp = NULL; - int i, matched = FALSE; + int i; + bool matched = false; + debug_decl(user_in_group, SUDO_DEBUG_NSS) if ((grlist = get_group_list(pw)) != NULL) { /* @@ -862,12 +933,12 @@ user_in_group(struct passwd *pw, const char *group) if (group[0] == '#') { gid_t gid = atoi(group + 1); if (gid == pw->pw_gid) { - matched = TRUE; + matched = true; goto done; } for (i = 0; i < grlist->ngids; i++) { if (gid == grlist->gids[i]) { - matched = TRUE; + matched = true; goto done; } } @@ -879,7 +950,7 @@ user_in_group(struct passwd *pw, const char *group) */ for (i = 0; i < grlist->ngroups; i++) { if (strcasecmp(group, grlist->groups[i]) == 0) { - matched = TRUE; + matched = true; goto done; } } @@ -887,7 +958,7 @@ user_in_group(struct passwd *pw, const char *group) /* Finally check against user's primary (passwd file) group. */ if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { if (strcasecmp(group, grp->gr_name) == 0) { - matched = TRUE; + matched = true; goto done; } } @@ -896,5 +967,5 @@ done: gr_delref(grp); grlist_delref(grlist); } - return matched; + debug_return_bool(matched); }