Use non-existing allocators in the passwd/group cache functions.

This commit is contained in:
Todd C. Miller
2015-05-27 10:26:49 -06:00
parent 40d72f26e4
commit 6b7be032af
3 changed files with 92 additions and 54 deletions

View File

@@ -28,6 +28,7 @@
# include <stdlib.h> # include <stdlib.h>
# endif # endif
#endif /* STDC_HEADERS */ #endif /* STDC_HEADERS */
#include <errno.h>
#include <usersec.h> #include <usersec.h>
#include <uinfo.h> #include <uinfo.h>
@@ -147,43 +148,53 @@ int usrinfo(int cmd, char *buf, int count);
* Look up administrative domain for user (SYSTEM in /etc/security/user) and * Look up administrative domain for user (SYSTEM in /etc/security/user) and
* set it as the default for the process. This ensures that password and * set it as the default for the process. This ensures that password and
* group lookups are made against the correct source (files, NIS, LDAP, etc). * group lookups are made against the correct source (files, NIS, LDAP, etc).
* Does not modify errno even on error since callers do not check rval.
*/ */
int int
aix_setauthdb_v1(char *user) aix_setauthdb_v1(char *user)
{ {
char *registry; char *registry;
int serrno = errno;
int rval = -1;
debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL) debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL)
if (user != NULL) { if (user != NULL) {
if (setuserdb(S_READ) != 0) { if (setuserdb(S_READ) != 0) {
sudo_warn(U_("unable to open userdb")); sudo_warn(U_("unable to open userdb"));
debug_return_int(-1); goto done;
} }
if (getuserattr(user, S_REGISTRY, &registry, SEC_CHAR) == 0) { if (getuserattr(user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
if (setauthdb(registry, NULL) != 0) { if (setauthdb(registry, NULL) != 0) {
sudo_warn(U_("unable to switch to registry \"%s\" for %s"), sudo_warn(U_("unable to switch to registry \"%s\" for %s"),
registry, user); registry, user);
debug_return_int(-1); goto done;
} }
} }
enduserdb(); enduserdb();
} }
debug_return_int(0); rval = 0;
done:
errno = serrno;
debug_return_int(rval);
} }
/* /*
* Restore the saved administrative domain, if any. * Restore the saved administrative domain, if any.
* Does not modify errno even on error since callers do not check rval.
*/ */
int int
aix_restoreauthdb_v1(void) aix_restoreauthdb_v1(void)
{ {
int serrno = errno;
int rval = 0;
debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL) debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL)
if (setauthdb(NULL, NULL) != 0) { if (setauthdb(NULL, NULL) != 0) {
sudo_warn(U_("unable to restore registry")); sudo_warn(U_("unable to restore registry"));
debug_return_int(-1); rval = -1;
} }
debug_return_int(0); errno = serrno;
debug_return_int(rval);
} }
#endif #endif

View File

@@ -46,6 +46,7 @@
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
# include <usersec.h> # include <usersec.h>
#endif /* HAVE_SETAUTHDB */ #endif /* HAVE_SETAUTHDB */
#include <errno.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@@ -103,7 +104,7 @@ sudo_pw_delref_item(void *v)
debug_decl(sudo_pw_delref_item, SUDOERS_DEBUG_NSS) debug_decl(sudo_pw_delref_item, SUDOERS_DEBUG_NSS)
if (--item->refcnt == 0) if (--item->refcnt == 0)
sudo_efree(item); free(item);
debug_return; debug_return;
} }
@@ -138,9 +139,11 @@ sudo_getpwuid(uid_t uid)
aix_setauthdb(IDtouser(uid)); aix_setauthdb(IDtouser(uid));
#endif #endif
item = sudo_make_pwitem(uid, NULL); item = sudo_make_pwitem(uid, NULL);
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
#endif
if (item == NULL) { if (item == NULL) {
item = calloc(1, sizeof(*item)); if (errno != ENOENT || (item = calloc(1, sizeof(*item))) == NULL) {
if (item == NULL) {
sudo_warnx(U_("unable to cache uid %u, out of memory"), sudo_warnx(U_("unable to cache uid %u, out of memory"),
(unsigned int) uid); (unsigned int) uid);
debug_return_ptr(NULL); debug_return_ptr(NULL);
@@ -163,9 +166,6 @@ sudo_getpwuid(uid_t uid)
item->refcnt = 0; item->refcnt = 0;
break; break;
} }
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
#endif
done: done:
item->refcnt++; item->refcnt++;
debug_return_ptr(item->d.pw); debug_return_ptr(item->d.pw);
@@ -179,7 +179,6 @@ sudo_getpwnam(const char *name)
{ {
struct cache_item key, *item; struct cache_item key, *item;
struct rbnode *node; struct rbnode *node;
size_t len;
debug_decl(sudo_getpwnam, SUDOERS_DEBUG_NSS) debug_decl(sudo_getpwnam, SUDOERS_DEBUG_NSS)
key.k.name = (char *) name; key.k.name = (char *) name;
@@ -194,10 +193,12 @@ sudo_getpwnam(const char *name)
aix_setauthdb((char *) name); aix_setauthdb((char *) name);
#endif #endif
item = sudo_make_pwitem((uid_t)-1, name); item = sudo_make_pwitem((uid_t)-1, name);
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
#endif
if (item == NULL) { if (item == NULL) {
len = strlen(name) + 1; const size_t len = strlen(name) + 1;
item = calloc(1, sizeof(*item) + len); if (errno != ENOENT || (item = calloc(1, sizeof(*item) + len)) == NULL) {
if (item == NULL) {
sudo_warnx(U_("unable to cache user %s, out of memory"), name); sudo_warnx(U_("unable to cache user %s, out of memory"), name);
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
@@ -218,9 +219,6 @@ sudo_getpwnam(const char *name)
item->refcnt = 0; item->refcnt = 0;
break; break;
} }
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
#endif
done: done:
item->refcnt++; item->refcnt++;
debug_return_ptr(item->d.pw); debug_return_ptr(item->d.pw);
@@ -258,7 +256,11 @@ sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
struct rbtree *pwcache; struct rbtree *pwcache;
struct rbnode *node; struct rbnode *node;
pwitem = sudo_ecalloc(1, len); pwitem = calloc(1, len);
if (pwitem == NULL) {
sudo_warnx(U_("unable to cache user %s, out of memory"), user);
debug_return_ptr(NULL);
}
pw = &pwitem->pw; pw = &pwitem->pw;
pw->pw_uid = uid; pw->pw_uid = uid;
pw->pw_gid = gid; pw->pw_gid = gid;
@@ -295,7 +297,7 @@ sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
item = node->data = &pwitem->cache; item = node->data = &pwitem->cache;
} else { } else {
/* Good entry, discard our fake one. */ /* Good entry, discard our fake one. */
sudo_efree(pwitem); free(pwitem);
} }
break; break;
case -1: case -1:
@@ -399,7 +401,7 @@ sudo_gr_delref_item(void *v)
debug_decl(sudo_gr_delref_item, SUDOERS_DEBUG_NSS) debug_decl(sudo_gr_delref_item, SUDOERS_DEBUG_NSS)
if (--item->refcnt == 0) if (--item->refcnt == 0)
sudo_efree(item); free(item);
debug_return; debug_return;
} }
@@ -432,7 +434,11 @@ sudo_getgrgid(gid_t gid)
*/ */
item = sudo_make_gritem(gid, NULL); item = sudo_make_gritem(gid, NULL);
if (item == NULL) { if (item == NULL) {
item = sudo_ecalloc(1, sizeof(*item)); if (errno != ENOENT || (item = calloc(1, sizeof(*item))) == NULL) {
sudo_warnx(U_("unable to cache gid %u, out of memory"),
(unsigned int) gid);
debug_return_ptr(NULL);
}
item->refcnt = 1; item->refcnt = 1;
item->k.gid = gid; item->k.gid = gid;
/* item->d.gr = NULL; */ /* item->d.gr = NULL; */
@@ -464,7 +470,6 @@ sudo_getgrnam(const char *name)
{ {
struct cache_item key, *item; struct cache_item key, *item;
struct rbnode *node; struct rbnode *node;
size_t len;
debug_decl(sudo_getgrnam, SUDOERS_DEBUG_NSS) debug_decl(sudo_getgrnam, SUDOERS_DEBUG_NSS)
key.k.name = (char *) name; key.k.name = (char *) name;
@@ -477,8 +482,11 @@ sudo_getgrnam(const char *name)
*/ */
item = sudo_make_gritem((gid_t)-1, name); item = sudo_make_gritem((gid_t)-1, name);
if (item == NULL) { if (item == NULL) {
len = strlen(name) + 1; const size_t len = strlen(name) + 1;
item = sudo_ecalloc(1, sizeof(*item) + len); if (errno != ENOENT || (item = calloc(1, sizeof(*item) + len)) == NULL) {
sudo_warnx(U_("unable to cache group %s, out of memory"), name);
debug_return_ptr(NULL);
}
item->refcnt = 1; item->refcnt = 1;
item->k.name = (char *) item + sizeof(*item); item->k.name = (char *) item + sizeof(*item);
memcpy(item->k.name, name, len); memcpy(item->k.name, name, len);
@@ -522,7 +530,11 @@ sudo_fakegrnam(const char *group)
struct rbtree *grcache; struct rbtree *grcache;
struct rbnode *node; struct rbnode *node;
gritem = sudo_ecalloc(1, len); gritem = calloc(1, len);
if (gritem == NULL) {
sudo_warnx(U_("unable to cache group %s, out of memory"), group);
debug_return_ptr(NULL);
}
gr = &gritem->gr; gr = &gritem->gr;
gr->gr_gid = (gid_t) sudo_strtoid(group + 1, NULL, NULL, &errstr); gr->gr_gid = (gid_t) sudo_strtoid(group + 1, NULL, NULL, &errstr);
gr->gr_name = (char *)(gritem + 1); gr->gr_name = (char *)(gritem + 1);
@@ -530,7 +542,7 @@ sudo_fakegrnam(const char *group)
if (errstr != NULL) { if (errstr != NULL) {
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG,
"gid %s %s", group, errstr); "gid %s %s", group, errstr);
sudo_efree(gritem); free(gritem);
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
@@ -556,7 +568,7 @@ sudo_fakegrnam(const char *group)
item = node->data = &gritem->cache; item = node->data = &gritem->cache;
} else { } else {
/* Good entry, discard our fake one. */ /* Good entry, discard our fake one. */
sudo_efree(gritem); free(gritem);
} }
break; break;
case -1: case -1:
@@ -585,7 +597,7 @@ sudo_grlist_delref_item(void *v)
debug_decl(sudo_gr_delref_item, SUDOERS_DEBUG_NSS) debug_decl(sudo_gr_delref_item, SUDOERS_DEBUG_NSS)
if (--item->refcnt == 0) if (--item->refcnt == 0)
sudo_efree(item); free(item);
debug_return; debug_return;
} }
@@ -654,7 +666,6 @@ sudo_get_grlist(const struct passwd *pw)
{ {
struct cache_item key, *item; struct cache_item key, *item;
struct rbnode *node; struct rbnode *node;
size_t len;
debug_decl(sudo_get_grlist, SUDOERS_DEBUG_NSS) debug_decl(sudo_get_grlist, SUDOERS_DEBUG_NSS)
key.k.name = pw->pw_name; key.k.name = pw->pw_name;
@@ -667,13 +678,8 @@ sudo_get_grlist(const struct passwd *pw)
*/ */
item = sudo_make_grlist_item(pw, NULL, NULL); item = sudo_make_grlist_item(pw, NULL, NULL);
if (item == NULL) { if (item == NULL) {
/* Should not happen. */ /* Out of memory? */
len = strlen(pw->pw_name) + 1; debug_return_ptr(NULL);
item = sudo_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; */
} }
switch (rbinsert(grlist_cache, item, NULL)) { switch (rbinsert(grlist_cache, item, NULL)) {
case 1: case 1:

View File

@@ -43,6 +43,7 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@@ -79,6 +80,8 @@ do { \
* Dynamically allocate space for a struct item plus the key and data * 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 * elements. If name is non-NULL it is used as the key, else the
* uid is the key. Fills in datum from struct password. * uid is the key. Fills in datum from struct password.
* Returns NULL on malloc error or unknown name/id, setting errno
* to ENOMEM or ENOENT respectively.
*/ */
struct cache_item * struct cache_item *
sudo_make_pwitem(uid_t uid, const char *name) sudo_make_pwitem(uid_t uid, const char *name)
@@ -92,8 +95,10 @@ sudo_make_pwitem(uid_t uid, const char *name)
/* Look up by name or uid. */ /* Look up by name or uid. */
pw = name ? getpwnam(name) : getpwuid(uid); pw = name ? getpwnam(name) : getpwuid(uid);
if (pw == NULL) if (pw == NULL) {
errno = ENOENT;
debug_return_ptr(NULL); debug_return_ptr(NULL);
}
/* If shell field is empty, expand to _PATH_BSHELL. */ /* If shell field is empty, expand to _PATH_BSHELL. */
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
@@ -116,7 +121,8 @@ sudo_make_pwitem(uid_t uid, const char *name)
total += strlen(name) + 1; total += strlen(name) + 1;
/* Allocate space for struct item, struct passwd and the strings. */ /* Allocate space for struct item, struct passwd and the strings. */
pwitem = sudo_ecalloc(1, total); if ((pwitem = calloc(1, total)) == NULL)
debug_return_ptr(NULL);
newpw = &pwitem->pw; newpw = &pwitem->pw;
/* /*
@@ -154,6 +160,8 @@ sudo_make_pwitem(uid_t uid, const char *name)
* Dynamically allocate space for a struct item plus the key and data * 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 * elements. If name is non-NULL it is used as the key, else the
* gid is the key. Fills in datum from struct group. * gid is the key. Fills in datum from struct group.
* Returns NULL on malloc error or unknown name/id, setting errno
* to ENOMEM or ENOENT respectively.
*/ */
struct cache_item * struct cache_item *
sudo_make_gritem(gid_t gid, const char *name) sudo_make_gritem(gid_t gid, const char *name)
@@ -166,8 +174,10 @@ sudo_make_gritem(gid_t gid, const char *name)
/* Look up by name or gid. */ /* Look up by name or gid. */
gr = name ? getgrnam(name) : getgrgid(gid); gr = name ? getgrnam(name) : getgrgid(gid);
if (gr == NULL) if (gr == NULL) {
errno = ENOENT;
debug_return_ptr(NULL); debug_return_ptr(NULL);
}
/* Allocate in one big chunk for easy freeing. */ /* Allocate in one big chunk for easy freeing. */
nsize = psize = nmem = 0; nsize = psize = nmem = 0;
@@ -183,7 +193,8 @@ sudo_make_gritem(gid_t gid, const char *name)
if (name != NULL) if (name != NULL)
total += strlen(name) + 1; total += strlen(name) + 1;
gritem = sudo_ecalloc(1, total); if ((gritem = calloc(1, total)) == NULL)
debug_return_ptr(NULL);
/* /*
* Copy in group contents and make strings relative to space * Copy in group contents and make strings relative to space
@@ -233,7 +244,7 @@ sudo_make_grlist_item(const struct passwd *pw, char * const *unused1,
struct cache_item_grlist *grlitem; struct cache_item_grlist *grlitem;
struct group_list *grlist; struct group_list *grlist;
GETGROUPS_T *gids; GETGROUPS_T *gids;
struct group *grp; struct group *grp = NULL;
int i, ngids, groupname_len; int i, ngids, groupname_len;
debug_decl(sudo_make_grlist_item, SUDOERS_DEBUG_NSS) debug_decl(sudo_make_grlist_item, SUDOERS_DEBUG_NSS)
@@ -245,30 +256,33 @@ sudo_make_grlist_item(const struct passwd *pw, char * const *unused1,
} else { } else {
if (sudo_user.max_groups > 0) { if (sudo_user.max_groups > 0) {
ngids = sudo_user.max_groups; ngids = sudo_user.max_groups;
gids = sudo_emallocarray(ngids, sizeof(GETGROUPS_T)); gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T));
if (gids == NULL)
debug_return_ptr(NULL);
(void)getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids); (void)getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids);
} else { } else {
ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2; ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
if (ngids < 0) if (ngids < 0)
ngids = NGROUPS_MAX * 2; ngids = NGROUPS_MAX * 2;
gids = sudo_emallocarray(ngids, sizeof(GETGROUPS_T)); gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T));
if (gids == NULL)
debug_return_ptr(NULL);
if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {
sudo_efree(gids); free(gids);
gids = sudo_emallocarray(ngids, sizeof(GETGROUPS_T)); gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T));
if (gids == NULL)
debug_return_ptr(NULL);
if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1)
ngids = -1; ngids = -1;
} }
} }
} }
if (ngids <= 0) { if (ngids <= 0) {
sudo_efree(gids); free(gids);
errno = ENOENT;
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
#ifdef HAVE_SETAUTHDB
aix_setauthdb((char *) pw->pw_name);
#endif
#ifdef _SC_LOGIN_NAME_MAX #ifdef _SC_LOGIN_NAME_MAX
groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32); groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32);
#else #else
@@ -283,7 +297,10 @@ sudo_make_grlist_item(const struct passwd *pw, char * const *unused1,
total += groupname_len * ngids; total += groupname_len * ngids;
again: again:
grlitem = sudo_ecalloc(1, total); if ((grlitem = calloc(1, total)) == NULL) {
free(gids);
debug_return_ptr(NULL);
}
/* /*
* Copy in group list and make pointers relative to space * Copy in group list and make pointers relative to space
@@ -314,13 +331,17 @@ again:
/* /*
* Resolve and store group names by ID. * Resolve and store group names by ID.
*/ */
#ifdef HAVE_SETAUTHDB
if (grp == NULL)
aix_setauthdb((char *) pw->pw_name);
#endif
ngroups = 0; ngroups = 0;
for (i = 0; i < ngids; i++) { for (i = 0; i < ngids; i++) {
if ((grp = sudo_getgrgid(gids[i])) != NULL) { if ((grp = sudo_getgrgid(gids[i])) != NULL) {
len = strlen(grp->gr_name) + 1; len = strlen(grp->gr_name) + 1;
if (cp - (char *)grlitem + len > total) { if (cp - (char *)grlitem + len > total) {
total += len + groupname_len; total += len + groupname_len;
sudo_efree(grlitem); free(grlitem);
sudo_gr_delref(grp); sudo_gr_delref(grp);
goto again; goto again;
} }
@@ -331,7 +352,7 @@ again:
} }
} }
grlist->ngroups = ngroups; grlist->ngroups = ngroups;
sudo_efree(gids); free(gids);
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
aix_restoreauthdb(); aix_restoreauthdb();