Also switch to non-exiting allocators in affected code blocks.
a->type = type;
/* a->used = false; */
HLTQ_TO_TAILQ(&a->members, members, entries);
- if (rbinsert(aliases, a)) {
+ switch (rbinsert(aliases, a, NULL)) {
+ case 1:
snprintf(errbuf, sizeof(errbuf), N_("Alias `%s' already defined"), name);
alias_free(a);
debug_return_str(errbuf);
+ case -1:
+ strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf));
+ alias_free(a);
+ debug_return_str(errbuf);
}
debug_return_str(NULL);
}
debug_return_ptr(rbdelete(aliases, node));
}
-void
+bool
init_aliases(void)
{
debug_decl(init_aliases, SUDOERS_DEBUG_ALIAS)
rbdestroy(aliases, alias_free);
aliases = rbcreate(alias_compare);
- debug_return;
+ debug_return_bool(aliases != NULL);
}
* Free up space used by data structures from a previous parser run and sets
* the current sudoers file to path.
*/
-void
+bool
init_parser(const char *path, bool quiet)
{
struct member_list *binding;
struct defaults *d, *d_next;
struct userspec *us, *us_next;
+ bool rval = true;
debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
}
TAILQ_INIT(&defaults);
- init_aliases();
-
init_lexer();
- sudo_efree(sudoers);
- sudoers = path ? sudo_estrdup(path) : NULL;
+ if (!init_aliases()) {
+ sudo_warnx(U_("unable to allocate memory"));
+ rval = false;
+ }
+
+ free(sudoers);
+ if (path != NULL) {
+ if ((sudoers = strdup(path)) == NULL) {
+ sudo_warnx(U_("unable to allocate memory"));
+ rval = false;
+ }
+ } else {
+ sudoers = NULL;
+ }
parse_error = false;
errorlineno = -1;
errorfile = sudoers;
sudoers_warnings = !quiet;
- debug_return;
+ debug_return_bool(rval);
}
-#line 919 "gram.c"
+#line 930 "gram.c"
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
#if defined(__cplusplus) || defined(__STDC__)
static int yygrowstack(void)
yyval.member = new_member(yyvsp[0].string, WORD);
}
break;
-#line 1828 "gram.c"
+#line 1839 "gram.c"
}
yyssp -= yym;
yystate = *yyssp;
* Free up space used by data structures from a previous parser run and sets
* the current sudoers file to path.
*/
-void
+bool
init_parser(const char *path, bool quiet)
{
struct member_list *binding;
struct defaults *d, *d_next;
struct userspec *us, *us_next;
+ bool rval = true;
debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
}
TAILQ_INIT(&defaults);
- init_aliases();
-
init_lexer();
- sudo_efree(sudoers);
- sudoers = path ? sudo_estrdup(path) : NULL;
+ if (!init_aliases()) {
+ sudo_warnx(U_("unable to allocate memory"));
+ rval = false;
+ }
+
+ free(sudoers);
+ if (path != NULL) {
+ if ((sudoers = strdup(path)) == NULL) {
+ sudo_warnx(U_("unable to allocate memory"));
+ rval = false;
+ }
+ } else {
+ sudoers = NULL;
+ }
parse_error = false;
errorlineno = -1;
errorfile = sudoers;
sudoers_warnings = !quiet;
- debug_return;
+ debug_return_bool(rval);
}
bindtextdomain("sudoers", LOCALEDIR);
- sudo_setpwent();
- sudo_setgrent();
+ if (sudo_setpwent() == -1 || sudo_setgrent() == -1) {
+ sudo_warnx(U_("unable to allocate memory"));
+ debug_return_int(-1);
+ }
/* Initialize the debug subsystem. */
for (cur = settings; *cur != NULL; cur++) {
void alias_apply(int (*func)(void *, void *), void *cookie);
void alias_free(void *a);
void alias_put(struct alias *a);
-void init_aliases(void);
+bool init_aliases(void);
/* gram.c */
-void init_parser(const char *, bool);
+bool init_parser(const char *, bool);
/* match_addr.c */
bool addr_matches(char *n);
#endif
item = sudo_make_pwitem(uid, NULL);
if (item == NULL) {
- item = sudo_ecalloc(1, sizeof(*item));
+ item = calloc(1, sizeof(*item));
+ if (item == NULL) {
+ sudo_warnx(U_("unable to cache uid %u, out of memory"),
+ (unsigned int) uid);
+ debug_return_ptr(NULL);
+ }
item->refcnt = 1;
item->k.uid = uid;
/* item->d.pw = NULL; */
}
- if (rbinsert(pwcache_byuid, item) != NULL) {
+ switch (rbinsert(pwcache_byuid, item, NULL)) {
+ case 1:
/* should not happen */
sudo_warnx(U_("unable to cache uid %u, already exists"),
(unsigned int) uid);
item->refcnt = 0;
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache uid %u, out of memory"),
+ (unsigned int) uid);
+ item->refcnt = 0;
+ break;
}
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
item = sudo_make_pwitem((uid_t)-1, name);
if (item == NULL) {
len = strlen(name) + 1;
- item = sudo_ecalloc(1, sizeof(*item) + len);
+ item = calloc(1, sizeof(*item) + len);
+ if (item == NULL) {
+ sudo_warnx(U_("unable to cache user %s, out of memory"), name);
+ debug_return_ptr(NULL);
+ }
item->refcnt = 1;
item->k.name = (char *) item + sizeof(*item);
memcpy(item->k.name, name, len);
/* item->d.pw = NULL; */
}
- if (rbinsert(pwcache_byname, item) != NULL) {
+ switch (rbinsert(pwcache_byname, item, NULL)) {
+ case 1:
/* should not happen */
sudo_warnx(U_("unable to cache user %s, already exists"), name);
item->refcnt = 0;
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache user %s, out of memory"), name);
+ item->refcnt = 0;
+ break;
}
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
item->refcnt = 1;
item->d.pw = pw;
if (i == 0) {
- /* Store by uid if it doesn't already exist. */
+ /* Store by uid. */
item->k.uid = pw->pw_uid;
pwcache = pwcache_byuid;
} else {
- /* Store by name if it doesn't already exist. */
+ /* Store by name. */
item->k.name = pw->pw_name;
pwcache = pwcache_byname;
}
- if ((node = rbinsert(pwcache, item)) != NULL) {
+ switch (rbinsert(pwcache, item, &node)) {
+ case 1:
/* Already exists. */
item = node->data;
if (item->d.pw == NULL) {
/* Good entry, discard our fake one. */
sudo_efree(pwitem);
}
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache user %s, out of memory"), user);
+ item->refcnt = 0;
+ break;
}
}
item->refcnt++;
debug_return_ptr(sudo_mkpwent(user, uid, gid, NULL, NULL));
}
-void
+int
sudo_setpwent(void)
{
debug_decl(sudo_setpwent, SUDOERS_DEBUG_NSS)
- setpwent();
if (pwcache_byuid == NULL)
pwcache_byuid = rbcreate(cmp_pwuid);
if (pwcache_byname == NULL)
pwcache_byname = rbcreate(cmp_pwnam);
+ if (pwcache_byuid == NULL || pwcache_byname == NULL)
+ debug_return_int(-1);
- debug_return;
+ setpwent();
+
+ debug_return_int(0);
}
void
item->k.gid = gid;
/* item->d.gr = NULL; */
}
- if (rbinsert(grcache_bygid, item) != NULL) {
+ switch (rbinsert(grcache_bygid, item, NULL)) {
+ case 1:
/* should not happen */
sudo_warnx(U_("unable to cache gid %u, already exists"),
(unsigned int) gid);
item->refcnt = 0;
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache gid %u, out of memory"),
+ (unsigned int) gid);
+ item->refcnt = 0;
+ break;
}
done:
item->refcnt++;
memcpy(item->k.name, name, len);
/* item->d.gr = NULL; */
}
- if (rbinsert(grcache_byname, item) != NULL) {
+ switch (rbinsert(grcache_byname, item, NULL)) {
+ case 1:
/* should not happen */
sudo_warnx(U_("unable to cache group %s, already exists"), name);
item->refcnt = 0;
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache group %s, out of memory"), name);
+ item->refcnt = 0;
+ break;
}
done:
item->refcnt++;
gritem->cache.k.name = gr->gr_name;
grcache = grcache_byname;
}
- if ((node = rbinsert(grcache, item)) != NULL) {
+ switch (rbinsert(grcache, item, &node)) {
+ case 1:
/* Already exists. */
item = node->data;
if (item->d.gr == NULL) {
/* Good entry, discard our fake one. */
sudo_efree(gritem);
}
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache group %s, out of memory"), group);
+ item->refcnt = 0;
+ break;
}
}
item->refcnt++;
debug_return;
}
-void
+int
sudo_setgrent(void)
{
debug_decl(sudo_setgrent, SUDOERS_DEBUG_NSS)
- setgrent();
if (grcache_bygid == NULL)
grcache_bygid = rbcreate(cmp_grgid);
if (grcache_byname == NULL)
grcache_byname = rbcreate(cmp_grnam);
if (grlist_cache == NULL)
grlist_cache = rbcreate(cmp_grnam);
+ if (grcache_bygid == NULL || grcache_byname == NULL || grlist_cache == NULL)
+ debug_return_int(-1);
- debug_return;
+ setgrent();
+
+ debug_return_int(0);
}
void
memcpy(item->k.name, pw->pw_name, len);
/* item->d.grlist = NULL; */
}
- if (rbinsert(grlist_cache, item) != NULL) {
+ switch (rbinsert(grlist_cache, item, NULL)) {
+ case 1:
/* should not happen */
sudo_warnx(U_("unable to cache group list for %s, already exists"),
pw->pw_name);
item->refcnt = 0;
+ break;
+ case -1:
+ /* can't cache item, just return it */
+ sudo_warnx(U_("unable to cache group list for %s, out of memory"),
+ pw->pw_name);
+ item->refcnt = 0;
+ break;
}
done:
item->refcnt++;
sudo_warnx(U_("unable to parse groups for %s"), pw->pw_name);
debug_return_int(-1);
}
- if (rbinsert(grlist_cache, item) != NULL) {
+ switch (rbinsert(grlist_cache, item, NULL)) {
+ case 1:
sudo_warnx(U_("unable to cache group list for %s, already exists"),
pw->pw_name);
sudo_grlist_delref_item(item);
+ break;
+ case -1:
+ sudo_warnx(U_("unable to cache group list for %s, out of memory"),
+ pw->pw_name);
+ sudo_grlist_delref_item(item);
+ debug_return_int(-1);
}
}
debug_return_int(0);
/*
* Create a red black tree struct using the specified compare routine.
- * Allocates and returns the initialized (empty) tree.
+ * Allocates and returns the initialized (empty) tree or NULL if
+ * memory cannot be allocated.
*/
struct rbtree *
rbcreate(int (*compar)(const void *, const void*))
struct rbtree *tree;
debug_decl(rbcreate, SUDOERS_DEBUG_RBTREE)
- tree = sudo_emalloc(sizeof(*tree));
- tree->compar = compar;
-
- /*
- * We use a self-referencing sentinel node called nil to simplify the
- * code by avoiding the need to check for NULL pointers.
- */
- tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
- tree->nil.color = black;
- tree->nil.data = NULL;
-
- /*
- * Similarly, the fake root node keeps us from having to worry
- * about splitting the root.
- */
- tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
- tree->root.color = black;
- tree->root.data = NULL;
+ if ((tree = malloc(sizeof(*tree))) != NULL) {
+ tree->compar = compar;
+
+ /*
+ * We use a self-referencing sentinel node called nil to simplify the
+ * code by avoiding the need to check for NULL pointers.
+ */
+ tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
+ tree->nil.color = black;
+ tree->nil.data = NULL;
+
+ /*
+ * Similarly, the fake root node keeps us from having to worry
+ * about splitting the root.
+ */
+ tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
+ tree->root.color = black;
+ tree->root.data = NULL;
+ }
debug_return_ptr(tree);
}
/*
* Insert data pointer into a redblack tree.
- * Returns a NULL pointer on success. If a node matching "data"
- * already exists, a pointer to the existant node is returned.
+ * Returns a 0 on success, 1 if a node matching "data" already exists
+ * (filling in "existing" if not NULL), or -1 on malloc() failure.
*/
-struct rbnode *
-rbinsert(struct rbtree *tree, void *data)
+int
+rbinsert(struct rbtree *tree, void *data, struct rbnode **existing)
{
struct rbnode *node = rbfirst(tree);
struct rbnode *parent = rbroot(tree);
/* Find correct insertion point. */
while (node != rbnil(tree)) {
parent = node;
- if ((res = tree->compar(data, node->data)) == 0)
- debug_return_ptr(node);
+ if ((res = tree->compar(data, node->data)) == 0) {
+ if (existing != NULL)
+ *existing = node;
+ debug_return_int(1);
+ }
node = res < 0 ? node->left : node->right;
}
- node = sudo_emalloc(sizeof(*node));
+ node = malloc(sizeof(*node));
+ if (node == NULL)
+ debug_return_int(-1);
node->data = data;
node->left = node->right = rbnil(tree);
node->parent = parent;
}
}
rbfirst(tree)->color = black; /* first node is always black */
- debug_return_ptr(NULL);
+ debug_return_int(0);
}
/*
rbdestroy_int(tree, node->right, destroy);
if (destroy != NULL)
destroy(node->data);
- sudo_efree(node);
+ free(node);
}
debug_return;
}
/*
- * Destroy the specified tree, calling the destructor destroy
+ * Destroy the specified tree, calling the destructor "destroy"
* for each node and then freeing the tree itself.
*/
void
{
debug_decl(rbdestroy, SUDOERS_DEBUG_RBTREE)
rbdestroy_int(tree, rbfirst(tree), destroy);
- sudo_efree(tree);
+ free(tree);
debug_return;
}
int rbapply_node(struct rbtree *, struct rbnode *,
int (*)(void *, void *), void *, enum rbtraversal);
struct rbnode *rbfind(struct rbtree *, void *);
-struct rbnode *rbinsert(struct rbtree *, void *);
+int rbinsert(struct rbtree *, void *, struct rbnode **);
struct rbtree *rbcreate(int (*)(const void *, const void *));
void rbdestroy(struct rbtree *, void (*)(void *));
bindtextdomain("sudoers", LOCALEDIR);
- sudo_setpwent();
- sudo_setgrent();
+ if (sudo_setpwent() == -1 || sudo_setgrent() == -1) {
+ sudo_warnx(U_("unable to allocate memory"));
+ debug_return_int(-1);
+ }
/* Register fatal/fatalx callback. */
sudo_fatal_callback_register(sudoers_cleanup);
void sudo_pw_addref(struct passwd *);
void sudo_pw_delref(struct passwd *);
int sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids);
-void sudo_setgrent(void);
-void sudo_setpwent(void);
+int sudo_setgrent(void);
+int sudo_setpwent(void);
void sudo_setspent(void);
/* timestr.c */
setgrfile(grfile);
if (pwfile)
setpwfile(pwfile);
- sudo_setpwent();
- sudo_setgrent();
+ if (sudo_setpwent() == -1 || sudo_setgrent() == -1)
+ sudo_fatalx(U_("unable to allocate memory"));
if (argc < 2) {
if (!dflag)
if (argc - optind != 0)
usage(1);
- sudo_setpwent();
- sudo_setgrent();
+ if (sudo_setpwent() == -1 || sudo_setgrent() == -1)
+ sudo_fatalx(U_("unable to allocate memory"));
/* Mock up a fake sudo_user struct. */
user_cmnd = user_base = "";
rval = false;
}
}
- rbinsert(alias_freelist, a);
+ if (rbinsert(alias_freelist, a, NULL) != 0)
+ rval = false;
}
debug_return_bool(rval);
}
debug_decl(check_aliases, SUDOERS_DEBUG_ALIAS)
alias_freelist = rbcreate(alias_compare);
+ if (alias_freelist == NULL) {
+ sudo_warnx(U_("unable to allocate memory"));
+ debug_return_int(-1);
+ }
/* Forward check. */
TAILQ_FOREACH(us, &userspecs, entries) {