#define cmp_grnam cmp_pwnam
+#define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item)))
+
struct cache_item {
+ unsigned int refcnt;
/* key */
union {
uid_t uid;
item->k.uid = pw->pw_uid;
}
item->d.pw = newpw;
+ item->refcnt = 1;
return(item);
}
+void
+pw_addref(struct passwd *pw)
+{
+ ptr_to_item(pw)->refcnt++;
+}
+
+static void
+pw_delref_item(void *v)
+{
+ struct cache_item *item = v;
+ struct passwd *pw = item->d.pw;
+
+ if (--item->refcnt == 0) {
+ if (pw != NULL && pw->pw_passwd != NULL) {
+ zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
+ if ((char *)pw->pw_passwd < (char *)pw ||
+ (char *)pw->pw_passwd > (char *)pw->pw_gecos)
+ efree(pw->pw_passwd); /* free if separate allocation */
+ }
+ efree(item);
+ }
+}
+
+void
+pw_delref(struct passwd *pw)
+{
+ pw_delref_item(ptr_to_item(pw));
+}
+
/*
* Get a password entry by uid and allocate space for it.
* Fills in pw_passwd from shadow file if necessary.
uid, item->d.pw->pw_name);
} else {
item = emalloc(sizeof(*item));
+ item->refcnt = 1;
item->k.uid = uid;
item->d.pw = NULL;
if (rbinsert(pwcache_byuid, item) != NULL)
aix_restoreauthdb();
#endif
done:
+ item->refcnt++;
return(item->d.pw);
}
} else {
len = strlen(name) + 1;
item = emalloc(sizeof(*item) + len);
+ item->refcnt = 1;
item->k.name = (char *) item + sizeof(*item);
memcpy(item->k.name, name, len);
item->d.pw = NULL;
aix_restoreauthdb();
#endif
done:
+ item->refcnt++;
return(item->d.pw);
}
pw->pw_shell = pw->pw_dir + 2;
memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
+ item->refcnt = 1;
+ item->d.pw = pw;
if (i == 0) {
/* Store by uid, overwriting cached version. */
item->k.uid = pw->pw_uid;
- item->d.pw = pw;
if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
- efree(node->data);
+ pw_delref_item(node->data);
node->data = item;
}
} else {
/* Store by name, overwriting cached version. */
item->k.name = pw->pw_name;
- item->d.pw = pw;
if ((node = rbinsert(pwcache_byname, item)) != NULL) {
- efree(node->data);
+ pw_delref_item(node->data);
node->data = item;
}
}
}
+ item->refcnt++;
return(pw);
}
-/*
- * Take a gid in string form "#123" and return a faked up group struct.
- */
-struct group *
-sudo_fakegrnam(const char *group)
-{
- struct cache_item *item;
- struct group *gr;
- struct rbnode *node;
- size_t len, namelen;
- int i;
-
- namelen = strlen(group);
- len = sizeof(*item) + sizeof(*gr) + 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));
- gr->gr_gid = (gid_t) atoi(group + 1);
- gr->gr_name = (char *)gr + sizeof(struct group);
- memcpy(gr->gr_name, group, namelen + 1);
-
- if (i == 0) {
- /* Store by gid, overwriting cached version. */
- item->k.gid = gr->gr_gid;
- item->d.gr = gr;
- if ((node = rbinsert(grcache_bygid, item)) != NULL) {
- efree(node->data);
- node->data = item;
- }
- } else {
- /* Store by name, overwriting cached version. */
- item->k.name = gr->gr_name;
- item->d.gr = gr;
- if ((node = rbinsert(grcache_byname, item)) != NULL) {
- efree(node->data);
- node->data = item;
- }
- }
- }
- return(gr);
-}
-
void
sudo_setpwent(void)
{
pwcache_byname = rbcreate(cmp_pwnam);
}
-#ifdef PURIFY
-static void pw_free(void *);
-
void
sudo_freepwcache(void)
{
if (pwcache_byuid != NULL) {
- rbdestroy(pwcache_byuid, pw_free);
+ rbdestroy(pwcache_byuid, pw_delref_item);
pwcache_byuid = NULL;
}
if (pwcache_byname != NULL) {
- rbdestroy(pwcache_byname, pw_free);
+ rbdestroy(pwcache_byname, pw_delref_item);
pwcache_byname = NULL;
}
}
-static void
-pw_free(void *v)
-{
- struct cache_item *item = (struct cache_item *) v;
- struct passwd *pw = item->d.pw;
-
- if (pw != NULL && pw->pw_passwd != NULL) {
- zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
- if ((char *)pw->pw_passwd < (char *)pw ||
- (char *)pw->pw_passwd > (char *)pw->pw_gecos)
- efree(pw->pw_passwd); /* free if separate allocation */
- }
- efree(item);
-}
-#endif /* PURIFY */
-
void
sudo_endpwent(void)
{
endpwent();
sudo_endspent();
-#ifdef PURIFY
- sudo_freepwcache(); /* XXX - use after free */
-#endif
+ sudo_freepwcache();
}
/*
item->k.gid = gr->gr_gid;
}
item->d.gr = newgr;
+ item->refcnt = 1;
return(item);
}
+void
+gr_addref(struct group *gr)
+{
+ ptr_to_item(gr)->refcnt++;
+}
+
+static void
+gr_delref_item(void *v)
+{
+ struct cache_item *item = v;
+
+ if (--item->refcnt == 0)
+ efree(item);
+}
+
+void
+gr_delref(struct group *gr)
+{
+ gr_delref_item(ptr_to_item(gr));
+}
+
/*
* Get a group entry by gid and allocate space for it.
*/
gid, key.d.gr->gr_name);
} else {
item = emalloc(sizeof(*item));
+ item->refcnt = 1;
item->k.gid = gid;
item->d.gr = NULL;
if (rbinsert(grcache_bygid, item) != NULL)
errorx(1, "unable to cache gid %lu, already exists, gid");
}
done:
+ item->refcnt++;
return(item->d.gr);
}
} else {
len = strlen(name) + 1;
item = emalloc(sizeof(*item) + len);
+ item->refcnt = 1;
item->k.name = (char *) item + sizeof(*item);
memcpy(item->k.name, name, len);
item->d.gr = NULL;
errorx(1, "unable to cache group %s, already exists", name);
}
done:
+ item->refcnt++;
return(item->d.gr);
}
+/*
+ * Take a gid in string form "#123" and return a faked up group struct.
+ */
+struct group *
+sudo_fakegrnam(const char *group)
+{
+ struct cache_item *item;
+ struct group *gr;
+ struct rbnode *node;
+ size_t len, namelen;
+ int i;
+
+ namelen = strlen(group);
+ len = sizeof(*item) + sizeof(*gr) + 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));
+ gr->gr_gid = (gid_t) atoi(group + 1);
+ gr->gr_name = (char *)gr + sizeof(struct group);
+ memcpy(gr->gr_name, group, namelen + 1);
+
+ item->refcnt = 1;
+ item->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) {
+ gr_delref_item(node->data);
+ node->data = item;
+ }
+ } else {
+ /* Store by name, overwriting cached version. */
+ item->k.name = gr->gr_name;
+ if ((node = rbinsert(grcache_byname, item)) != NULL) {
+ gr_delref_item(node->data);
+ node->data = item;
+ }
+ }
+ }
+ item->refcnt++;
+ return(gr);
+}
+
void
sudo_setgrent(void)
{
grcache_byname = rbcreate(cmp_grnam);
}
-#ifdef PURIFY
void
sudo_freegrcache(void)
{
if (grcache_bygid != NULL) {
- rbdestroy(grcache_bygid, free);
+ rbdestroy(grcache_bygid, gr_delref_item);
grcache_bygid = NULL;
}
if (grcache_byname != NULL) {
- rbdestroy(grcache_byname, NULL);
+ rbdestroy(grcache_byname, gr_delref_item);
grcache_byname = NULL;
}
}
-#endif /* PURIFY */
void
sudo_endgrent(void)
{
endgrent();
-#ifdef PURIFY
- sudo_freegrcache(); /* XXX - use after free */
-#endif
+ sudo_freegrcache();
}
int
int i;
#endif
struct group *grp;
+ int retval = FALSE;
#ifdef HAVE_SETAUTHDB
aix_setauthdb(pw->pw_name);
aix_restoreauthdb();
#endif
if (grp == NULL)
- return(FALSE);
+ goto done;
/* check against user's primary (passwd file) gid */
- if (grp->gr_gid == pw->pw_gid)
- return(TRUE);
+ if (grp->gr_gid == pw->pw_gid) {
+ retval = TRUE;
+ goto done;
+ }
#ifdef HAVE_MBR_CHECK_MEMBERSHIP
/* If we are matching the invoking user use the stashed uuid. */
if (strcmp(pw->pw_name, user_name) == 0) {
if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
- mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember)
- return(TRUE);
+ mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) {
+ retval = TRUE;
+ goto done;
+ }
} else {
if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 &&
mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
- mbr_check_membership(uu, gu, &ismember) == 0 && ismember)
- return(TRUE);
+ mbr_check_membership(uu, gu, &ismember) == 0 && ismember) {
+ retval = TRUE;
+ goto done;
+ }
}
#else /* HAVE_MBR_CHECK_MEMBERSHIP */
# ifdef HAVE_GETGROUPS
if (user_ngroups >= 0 &&
strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
for (i = 0; i < user_ngroups; i++) {
- if (grp->gr_gid == user_groups[i])
- return(TRUE);
+ if (grp->gr_gid == user_groups[i]) {
+ retval = TRUE;
+ goto done;
+ }
}
} else
# endif /* HAVE_GETGROUPS */
{
if (grp != NULL && grp->gr_mem != NULL) {
for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
- if (strcmp(*gr_mem, pw->pw_name) == 0)
- return(TRUE);
+ if (strcmp(*gr_mem, pw->pw_name) == 0) {
+ retval = TRUE;
+ goto done;
+ }
}
}
}
#endif /* HAVE_MBR_CHECK_MEMBERSHIP */
- return(FALSE);
+done:
+ gr_delref(grp);
+ return(retval);
}