/* * Copyright (c) 2004-2005m, 2007-2009 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif /* STDC_HEADERS */ #ifdef HAVE_STRING_H # include #else # ifdef HAVE_STRINGS_H # include # endif #endif /* HAVE_STRING_H */ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include "sudo.h" #include "parse.h" #include "redblack.h" #include #ifndef lint __unused static const char rcsid[] = "$Sudo: alias.c,v 1.18 2009/05/25 12:02:41 millert Exp $"; #endif /* lint */ /* * Globals */ struct rbtree *aliases; unsigned int alias_seqno; /* * Comparison function for the red-black tree. * Aliases are sorted by name with the type used as a tie-breaker. */ int alias_compare(v1, v2) const void *v1, *v2; { const struct alias *a1 = (const struct alias *)v1; const struct alias *a2 = (const struct alias *)v2; int res; if (v1 == NULL) res = -1; else if (v2 == NULL) res = 1; else if ((res = strcmp(a1->name, a2->name)) == 0) res = a1->type - a2->type; return(res); } /* * Search the tree for an alias with the specified name and type. * Returns a pointer to the alias structure or NULL if not found. */ struct alias * alias_find(name, type) char *name; int type; { struct alias key; struct rbnode *node; struct alias *a = NULL; key.name = name; key.type = type; if ((node = rbfind(aliases, &key)) != NULL) { /* * Compare the global sequence number with the one stored * in the alias. If they match then we've seen this alias * before and found a loop. */ a = node->data; if (a->seqno == alias_seqno) return(NULL); a->seqno = alias_seqno; } return(a); } /* * Add an alias to the aliases redblack tree. * Returns NULL on success and an error string on failure. */ char * alias_add(name, type, members) char *name; int type; struct member *members; { static char errbuf[512]; struct alias *a; a = emalloc(sizeof(*a)); a->name = name; a->type = type; a->seqno = 0; list2tq(&a->members, members); if (rbinsert(aliases, a)) { alias_free(a); snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name); return(errbuf); } return(NULL); } /* * Apply a function to each alias entry and pass in a cookie. */ void alias_apply(func, cookie) int (*func) __P((void *, void *)); void *cookie; { rbapply(aliases, func, cookie, inorder); } /* * Returns TRUE if there are no aliases, else FALSE. */ int no_aliases() { return(rbisempty(aliases)); } /* * Free memory used by an alias struct and its members. */ void alias_free(v) void *v; { struct alias *a = (struct alias *)v; struct member *m; struct sudo_command *c; void *next; efree(a->name); for (m = a->members.first; m != NULL; m = next) { next = m->next; if (m->type == COMMAND) { c = (struct sudo_command *) m->name; efree(c->cmnd); efree(c->args); } efree(m->name); efree(m); } efree(a); } /* * Find the named alias, remove it from the tree and return it. */ struct alias * alias_remove(name, type) char *name; int type; { struct rbnode *node; struct alias key, *a; key.name = name; key.type = type; if ((node = rbfind(aliases, &key)) == NULL) return(NULL); a = rbdelete(aliases, node); return(a); } void init_aliases() { if (aliases != NULL) rbdestroy(aliases, alias_free); aliases = rbcreate(alias_compare); }