1/* 2 * Copyright (c) 2004-2005, 2007-2010 3 * Todd C. Miller <Todd.Miller@courtesan.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 17 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 */ 19 20#include <config.h> 21 22#include <sys/types.h> 23#include <sys/param.h> 24#include <stdio.h> 25#ifdef STDC_HEADERS 26# include <stdlib.h> 27# include <stddef.h> 28#else 29# ifdef HAVE_STDLIB_H 30# include <stdlib.h> 31# endif 32#endif /* STDC_HEADERS */ 33#ifdef HAVE_STRING_H 34# include <string.h> 35#endif /* HAVE_STRING_H */ 36#ifdef HAVE_STRINGS_H 37# include <strings.h> 38#endif /* HAVE_STRING_H */ 39#ifdef HAVE_UNISTD_H 40# include <unistd.h> 41#endif /* HAVE_UNISTD_H */ 42#include <errno.h> 43 44#include "sudo.h" 45#include "parse.h" 46#include "redblack.h" 47#include <gram.h> 48 49/* 50 * Globals 51 */ 52struct rbtree *aliases; 53unsigned int alias_seqno; 54 55/* 56 * Comparison function for the red-black tree. 57 * Aliases are sorted by name with the type used as a tie-breaker. 58 */ 59int 60alias_compare(v1, v2) 61 const void *v1, *v2; 62{ 63 const struct alias *a1 = (const struct alias *)v1; 64 const struct alias *a2 = (const struct alias *)v2; 65 int res; 66 67 if (v1 == NULL) 68 res = -1; 69 else if (v2 == NULL) 70 res = 1; 71 else if ((res = strcmp(a1->name, a2->name)) == 0) 72 res = a1->type - a2->type; 73 return res; 74} 75 76/* 77 * Search the tree for an alias with the specified name and type. 78 * Returns a pointer to the alias structure or NULL if not found. 79 */ 80struct alias * 81alias_find(name, type) 82 char *name; 83 int type; 84{ 85 struct alias key; 86 struct rbnode *node; 87 struct alias *a = NULL; 88 89 key.name = name; 90 key.type = type; 91 if ((node = rbfind(aliases, &key)) != NULL) { 92 /* 93 * Compare the global sequence number with the one stored 94 * in the alias. If they match then we've seen this alias 95 * before and found a loop. 96 */ 97 a = node->data; 98 if (a->seqno == alias_seqno) { 99 errno = ELOOP; 100 return NULL; 101 } 102 a->seqno = alias_seqno; 103 } else { 104 errno = ENOENT; 105 } 106 return a; 107} 108 109/* 110 * Add an alias to the aliases redblack tree. 111 * Returns NULL on success and an error string on failure. 112 */ 113char * 114alias_add(name, type, members) 115 char *name; 116 int type; 117 struct member *members; 118{ 119 static char errbuf[512]; 120 struct alias *a; 121 122 a = ecalloc(1, sizeof(*a)); 123 a->name = name; 124 a->type = type; 125 /* a->seqno = 0; */ 126 list2tq(&a->members, members); 127 if (rbinsert(aliases, a)) { 128 snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name); 129 alias_free(a); 130 return errbuf; 131 } 132 return NULL; 133} 134 135/* 136 * Apply a function to each alias entry and pass in a cookie. 137 */ 138void 139alias_apply(func, cookie) 140 int (*func) __P((void *, void *)); 141 void *cookie; 142{ 143 rbapply(aliases, func, cookie, inorder); 144} 145 146/* 147 * Returns TRUE if there are no aliases, else FALSE. 148 */ 149int 150no_aliases() 151{ 152 return rbisempty(aliases); 153} 154 155/* 156 * Free memory used by an alias struct and its members. 157 */ 158void 159alias_free(v) 160 void *v; 161{ 162 struct alias *a = (struct alias *)v; 163 struct member *m; 164 struct sudo_command *c; 165 void *next; 166 167 efree(a->name); 168 for (m = a->members.first; m != NULL; m = next) { 169 next = m->next; 170 if (m->type == COMMAND) { 171 c = (struct sudo_command *) m->name; 172 efree(c->cmnd); 173 efree(c->args); 174 } 175 efree(m->name); 176 efree(m); 177 } 178 efree(a); 179} 180 181/* 182 * Find the named alias, remove it from the tree and return it. 183 */ 184struct alias * 185alias_remove(name, type) 186 char *name; 187 int type; 188{ 189 struct rbnode *node; 190 struct alias key; 191 192 key.name = name; 193 key.type = type; 194 if ((node = rbfind(aliases, &key)) == NULL) { 195 errno = ENOENT; 196 return NULL; 197 } 198 return rbdelete(aliases, node); 199} 200 201void 202init_aliases() 203{ 204 if (aliases != NULL) 205 rbdestroy(aliases, alias_free); 206 aliases = rbcreate(alias_compare); 207} 208