3 * Copyright (c) 1996, 1998-2004, 2007
4 * Todd C. Miller <Todd.Miller@courtesan.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20 * Sponsored in part by the Defense Advanced Research Projects
21 * Agency (DARPA) and Air Force Research Laboratory, Air Force
22 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
26 * XXX - the whole opFOO naming thing is somewhat bogus.
28 * XXX - the way things are stored for printmatches is stupid,
29 * they should be stored as elements in an array and then
30 * list_matches() can format things the way it wants.
35 #include <sys/types.h>
36 #include <sys/param.h>
45 #endif /* STDC_HEADERS */
49 # ifdef HAVE_STRINGS_H
52 #endif /* HAVE_STRING_H */
55 #endif /* HAVE_UNISTD_H */
57 #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
59 #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
62 #endif /* HAVE_LSEARCH */
68 #include "emul/search.h"
69 #endif /* HAVE_LSEARCH */
72 __unused static const char rcsid[] = "$Sudo: parse.yacc,v 1.204.2.9 2007/11/21 18:15:49 millert Exp $";
78 extern int sudolineno, parse_error;
80 int clearaliases = TRUE;
81 int printmatches = FALSE;
85 int used_runas = FALSE;
95 #define SETMATCH(_var, _val) do { \
96 if ((_var) == UNSPEC || (_val) != NOMATCH) \
100 #define SETNMATCH(_var, _val) do { \
101 if ((_val) != NOMATCH) \
103 else if ((_var) == UNSPEC) \
107 #define SETENV_RESET \
108 if (setenv_ok == IMPLIED) setenv_ok = def_setenv ? TRUE : UNSPEC
111 * The matching stack, initial space allocated in init_parser().
113 struct matchstack *match;
114 int top = 0, stacksize = 0;
118 if (top >= stacksize) { \
119 while ((stacksize += STACKINCREMENT) < top); \
120 match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
122 match[top].user = UNSPEC; \
123 match[top].cmnd = UNSPEC; \
124 match[top].host = UNSPEC; \
125 match[top].runas = UNSPEC; \
126 match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
127 match[top].noexec = def_noexec ? TRUE : UNSPEC; \
128 match[top].setenv = def_setenv ? TRUE : UNSPEC; \
134 if (top >= stacksize) { \
135 while ((stacksize += STACKINCREMENT) < top); \
136 match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
138 match[top].user = match[top-1].user; \
139 match[top].cmnd = match[top-1].cmnd; \
140 match[top].host = match[top-1].host; \
141 match[top].runas = match[top-1].runas; \
142 match[top].nopass = match[top-1].nopass; \
143 match[top].noexec = match[top-1].noexec; \
144 match[top].setenv = match[top-1].setenv; \
151 yyerror("matching stack underflow"); \
158 * For testing if foo_matches variable was set to TRUE or FALSE
160 #define MATCHED(_v) ((_v) >= 0)
163 * Shortcuts for append()
165 #define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
166 &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
168 #define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
169 &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
171 #define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
172 &ga_list[ga_list_len-1].entries_len, \
173 &ga_list[ga_list_len-1].entries_size, p)
176 * The stack for printmatches. A list of allowed commands for the user.
178 static struct command_match *cm_list = NULL;
179 static size_t cm_list_len = 0, cm_list_size = 0;
182 * List of Cmnd_Aliases and expansions for `sudo -l'
184 static int in_alias = FALSE;
185 static size_t ga_list_len = 0, ga_list_size = 0;
186 static struct generic_alias *ga_list = NULL;
189 * Does this Defaults list pertain to this user?
191 static int defaults_matches = FALSE;
196 static int add_alias __P((char *, int, int));
197 static void append __P((char *, char **, size_t *, size_t *, char *));
198 static void expand_ga_list __P((void));
199 static void expand_match_list __P((void));
200 static aliasinfo *find_alias __P((char *, int));
201 static void more_aliases __P((void));
202 void init_parser __P((void));
203 void yyerror __P((char *));
209 /* Save the line the first error occurred on. */
210 if (errorlineno == -1)
211 errorlineno = sudolineno ? sudolineno - 1 : 0;
214 (void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s,
215 sudolineno ? sudolineno - 1 : 0);
217 (void) fprintf(stderr, "<*> ");
227 struct sudo_command command;
231 %start file /* special start symbol */
232 %token <command> COMMAND /* absolute pathname w/ optional args */
233 %token <string> ALIAS /* an UPPERCASE alias name */
234 %token <string> DEFVAR /* a Defaults variable name */
235 %token <string> NTWKADDR /* w.x.y.z or ipv6 address */
236 %token <string> NETGROUP /* a netgroup (+NAME) */
237 %token <string> USERGROUP /* a usergroup (%NAME) */
238 %token <string> WORD /* a word */
239 %token <tok> DEFAULTS /* Defaults entry */
240 %token <tok> DEFAULTS_HOST /* Host-specific defaults entry */
241 %token <tok> DEFAULTS_USER /* User-specific defaults entry */
242 %token <tok> DEFAULTS_RUNAS /* Runas-specific defaults entry */
243 %token <tok> RUNAS /* ( runas_list ) */
244 %token <tok> NOPASSWD /* no passwd req for command */
245 %token <tok> PASSWD /* passwd req for command (default) */
246 %token <tok> NOEXEC /* preload dummy execve() for cmnd */
247 %token <tok> EXEC /* don't preload dummy execve() */
248 %token <tok> SETENV /* user may set environment for cmnd */
249 %token <tok> NOSETENV /* user may not set environment */
250 %token <tok> ALL /* ALL keyword */
251 %token <tok> COMMENT /* comment and/or carriage return */
252 %token <tok> HOSTALIAS /* Host_Alias keyword */
253 %token <tok> CMNDALIAS /* Cmnd_Alias keyword */
254 %token <tok> USERALIAS /* User_Alias keyword */
255 %token <tok> RUNASALIAS /* Runas_Alias keyword */
256 %token <tok> ':' '=' ',' '!' '+' '-' /* union member tokens */
260 * NOTE: these are not true booleans as there are actually 4 possible values:
261 * 1) TRUE (positive match)
262 * 0) FALSE (negative match due to a '!' somewhere)
263 * -1) NOMATCH (don't change the value of *_matches)
264 * -2) UNSPEC (uninitialized value)
268 %type <BOOLEAN> runasuser
269 %type <BOOLEAN> oprunasuser
270 %type <BOOLEAN> runaslist
283 | { push; } userlist privileges {
284 while (top && user_matches != TRUE)
287 | USERALIAS useraliases
289 | HOSTALIAS hostaliases
291 | CMNDALIAS cmndaliases
293 | RUNASALIAS runasaliases
299 defaults_line : defaults_type defaults_list
302 defaults_type : DEFAULTS {
303 defaults_matches = TRUE;
305 | DEFAULTS_USER { push; } userlist {
306 defaults_matches = user_matches;
309 | DEFAULTS_RUNAS { push; } runaslist {
310 defaults_matches = $3 == TRUE;
313 | DEFAULTS_HOST { push; } hostlist {
314 defaults_matches = host_matches;
319 defaults_list : defaults_entry
320 | defaults_entry ',' defaults_list
323 defaults_entry : DEFVAR {
324 if (defaults_matches == TRUE &&
325 !set_default($1, NULL, TRUE)) {
332 if (defaults_matches == TRUE &&
333 !set_default($2, NULL, FALSE)) {
340 if (defaults_matches == TRUE &&
341 !set_default($1, $3, TRUE)) {
349 if (defaults_matches == TRUE &&
350 !set_default($1, $3, '+')) {
358 if (defaults_matches == TRUE &&
359 !set_default($1, $3, '-')) {
368 privileges : privilege
369 | privileges ':' privilege
372 privilege : hostlist '=' cmndspeclist {
374 * We already did a push if necessary in
375 * cmndspec so just reset some values so
376 * the next 'privilege' gets a clean slate.
378 host_matches = UNSPEC;
379 runas_matches = UNSPEC;
380 no_passwd = def_authenticate ? UNSPEC : TRUE;
381 no_execve = def_noexec ? TRUE : UNSPEC;
382 setenv_ok = def_setenv ? TRUE : UNSPEC;
387 SETMATCH(host_matches, $1);
390 SETNMATCH(host_matches, $2);
398 if (addr_matches($1))
406 if (netgr_matches($1, user_host, user_shost, NULL))
414 if (hostname_matches(user_shost, user_host, $1) == 0)
421 aliasinfo *aip = find_alias($1, HOST_ALIAS);
424 /* could be an all-caps hostname */
427 else if (strcasecmp(user_shost, $1) == 0)
431 (void) fprintf(stderr,
432 "%s: undeclared Host_Alias `%s' referenced near line %d\n",
433 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
445 cmndspeclist : cmndspec
446 | cmndspeclist ',' cmndspec
449 cmndspec : { SETENV_RESET; } runasspec cmndtag opcmnd {
451 * Push the entry onto the stack if it is worth
452 * saving and reset cmnd_matches for next cmnd.
454 * We need to save at least one entry on
455 * the stack so sudoers_lookup() can tell that
456 * the user was listed in sudoers. Also, we
457 * need to be able to tell whether or not a
458 * user was listed for this specific host.
460 * If keepall is set and the user matches then
461 * we need to keep entries around too...
463 if (MATCHED(user_matches) &&
464 MATCHED(host_matches) &&
465 MATCHED(cmnd_matches) &&
466 MATCHED(runas_matches))
468 else if (MATCHED(user_matches) && (top == 1 ||
469 (top == 2 && MATCHED(host_matches) &&
470 !MATCHED(match[0].host))))
472 else if (user_matches == TRUE && keepall)
474 cmnd_matches = UNSPEC;
479 SETMATCH(cmnd_matches, $1);
482 if (printmatches == TRUE) {
483 if (in_alias == TRUE)
484 append_entries("!", ", ");
485 else if (host_matches == TRUE &&
486 user_matches == TRUE)
487 append_cmnd("!", NULL);
490 SETNMATCH(cmnd_matches, $3);
494 runasspec : /* empty */ {
495 if (printmatches == TRUE && host_matches == TRUE &&
496 user_matches == TRUE) {
497 if (runas_matches == UNSPEC) {
498 cm_list[cm_list_len].runas_len = 0;
500 /* Inherit runas data. */
501 cm_list[cm_list_len].runas =
502 estrdup(cm_list[cm_list_len-1].runas);
503 cm_list[cm_list_len].runas_len =
504 cm_list[cm_list_len-1].runas_len;
505 cm_list[cm_list_len].runas_size =
506 cm_list[cm_list_len-1].runas_size;
510 * If this is the first entry in a command list
511 * then check against default runas user.
513 if (runas_matches == UNSPEC) {
514 runas_matches = userpw_matches(def_runas_default,
515 *user_runas, runas_pw) ? TRUE : NOMATCH;
523 runaslist : oprunasuser { ; }
524 | runaslist ',' oprunasuser {
525 /* Later entries override earlier ones. */
533 oprunasuser : runasuser { ; }
535 if (printmatches == TRUE) {
536 if (in_alias == TRUE)
537 append_entries("!", ", ");
538 else if (host_matches == TRUE &&
539 user_matches == TRUE)
540 append_runas("!", ", ");
543 /* Set $$ to the negation of runasuser */
544 $$ = ($3 == NOMATCH ? NOMATCH : ! $3);
549 if (printmatches == TRUE) {
550 if (in_alias == TRUE)
551 append_entries($1, ", ");
552 else if (host_matches == TRUE &&
553 user_matches == TRUE)
554 append_runas($1, ", ");
556 if (userpw_matches($1, *user_runas, runas_pw))
564 if (printmatches == TRUE) {
565 if (in_alias == TRUE)
566 append_entries($1, ", ");
567 else if (host_matches == TRUE &&
568 user_matches == TRUE)
569 append_runas($1, ", ");
571 if (usergr_matches($1, *user_runas, runas_pw))
579 if (printmatches == TRUE) {
580 if (in_alias == TRUE)
581 append_entries($1, ", ");
582 else if (host_matches == TRUE &&
583 user_matches == TRUE)
584 append_runas($1, ", ");
586 if (netgr_matches($1, NULL, NULL, *user_runas))
594 aliasinfo *aip = find_alias($1, RUNAS_ALIAS);
596 if (printmatches == TRUE) {
597 if (in_alias == TRUE)
598 append_entries($1, ", ");
599 else if (host_matches == TRUE &&
600 user_matches == TRUE)
601 append_runas($1, ", ");
603 /* could be an all-caps username */
606 else if (strcmp($1, *user_runas) == 0)
610 (void) fprintf(stderr,
611 "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
612 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
624 if (printmatches == TRUE) {
625 if (in_alias == TRUE)
626 append_entries("ALL", ", ");
627 else if (host_matches == TRUE &&
628 user_matches == TRUE)
629 append_runas("ALL", ", ");
635 cmndtag : /* empty */ {
636 /* Inherit {NO,}{PASSWD,EXEC,SETENV} status. */
637 if (printmatches == TRUE && host_matches == TRUE &&
638 user_matches == TRUE) {
639 if (no_passwd == TRUE)
640 cm_list[cm_list_len].nopasswd = TRUE;
642 cm_list[cm_list_len].nopasswd = FALSE;
643 if (no_execve == TRUE)
644 cm_list[cm_list_len].noexecve = TRUE;
646 cm_list[cm_list_len].noexecve = FALSE;
647 if (setenv_ok == TRUE)
648 cm_list[cm_list_len].setenv = TRUE;
650 cm_list[cm_list_len].setenv = FALSE;
655 if (printmatches == TRUE && host_matches == TRUE &&
656 user_matches == TRUE)
657 cm_list[cm_list_len].nopasswd = TRUE;
661 if (printmatches == TRUE && host_matches == TRUE &&
662 user_matches == TRUE)
663 cm_list[cm_list_len].nopasswd = FALSE;
667 if (printmatches == TRUE && host_matches == TRUE &&
668 user_matches == TRUE)
669 cm_list[cm_list_len].noexecve = TRUE;
673 if (printmatches == TRUE && host_matches == TRUE &&
674 user_matches == TRUE)
675 cm_list[cm_list_len].noexecve = FALSE;
679 if (printmatches == TRUE && host_matches == TRUE &&
680 user_matches == TRUE)
681 cm_list[cm_list_len].setenv = TRUE;
685 if (printmatches == TRUE && host_matches == TRUE &&
686 user_matches == TRUE)
687 cm_list[cm_list_len].setenv = FALSE;
692 if (printmatches == TRUE) {
693 if (in_alias == TRUE)
694 append_entries("ALL", ", ");
695 else if (host_matches == TRUE &&
696 user_matches == TRUE) {
697 append_cmnd("ALL", NULL);
701 /* sudo "ALL" implies the SETENV tag */
702 if (setenv_ok == UNSPEC)
712 if (printmatches == TRUE) {
713 if (in_alias == TRUE)
714 append_entries($1, ", ");
715 else if (host_matches == TRUE &&
716 user_matches == TRUE) {
717 append_cmnd($1, NULL);
722 if ((aip = find_alias($1, CMND_ALIAS)))
726 (void) fprintf(stderr,
727 "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
728 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
739 if (printmatches == TRUE) {
740 if (in_alias == TRUE) {
741 append_entries($1.cmnd, ", ");
743 append_entries($1.args, " ");
745 if (host_matches == TRUE &&
746 user_matches == TRUE) {
747 append_cmnd($1.cmnd, NULL);
749 append_cmnd($1.args, " ");
754 if (command_matches($1.cmnd, $1.args))
764 hostaliases : hostalias
765 | hostaliases ':' hostalias
768 hostalias : ALIAS { push; } '=' hostlist {
769 if ((MATCHED(host_matches) || pedantic) &&
770 !add_alias($1, HOST_ALIAS, host_matches)) {
779 | hostlist ',' ophost
782 cmndaliases : cmndalias
783 | cmndaliases ':' cmndalias
788 if (printmatches == TRUE) {
790 /* Allocate space for ga_list if necessary. */
792 ga_list[ga_list_len-1].type = CMND_ALIAS;
793 ga_list[ga_list_len-1].alias = estrdup($1);
796 if ((MATCHED(cmnd_matches) || pedantic) &&
797 !add_alias($1, CMND_ALIAS, cmnd_matches)) {
804 if (printmatches == TRUE)
809 cmndlist : opcmnd { ; }
810 | cmndlist ',' opcmnd
813 runasaliases : runasalias
814 | runasaliases ':' runasalias
818 if (printmatches == TRUE) {
820 /* Allocate space for ga_list if necessary. */
822 ga_list[ga_list_len-1].type = RUNAS_ALIAS;
823 ga_list[ga_list_len-1].alias = estrdup($1);
826 if (($4 != NOMATCH || pedantic) &&
827 !add_alias($1, RUNAS_ALIAS, $4)) {
833 if (printmatches == TRUE)
838 useraliases : useralias
839 | useraliases ':' useralias
842 useralias : ALIAS { push; } '=' userlist {
843 if ((MATCHED(user_matches) || pedantic) &&
844 !add_alias($1, USER_ALIAS, user_matches)) {
854 | userlist ',' opuser
858 SETMATCH(user_matches, $1);
861 SETNMATCH(user_matches, $2);
866 if (userpw_matches($1, user_name, sudo_user.pw))
873 if (usergr_matches($1, user_name, sudo_user.pw))
880 if (netgr_matches($1, NULL, NULL, user_name))
887 aliasinfo *aip = find_alias($1, USER_ALIAS);
889 /* could be an all-caps username */
892 else if (strcmp($1, user_name) == 0)
896 (void) fprintf(stderr,
897 "%s: undeclared User_Alias `%s' referenced near line %d\n",
898 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
915 #define MOREALIASES (32)
916 aliasinfo *aliases = NULL;
922 * Compare two aliasinfo structures, strcmp() style.
923 * Note that we do *not* compare their values.
930 aliasinfo *ai1, *ai2;
932 ai1 = (aliasinfo *) a1;
933 ai2 = (aliasinfo *) a2;
934 if ((r = strcmp(ai1->name, ai2->name)) == 0)
935 r = ai1->type - ai2->type;
941 * Compare two generic_alias structures, strcmp() style.
944 genaliascmp(entry, key)
945 const VOID *entry, *key;
948 struct generic_alias *ga1, *ga2;
950 ga1 = (struct generic_alias *) key;
951 ga2 = (struct generic_alias *) entry;
952 if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
953 r = ga1->type - ga2->type;
960 * Adds the named alias of the specified type to the aliases list.
963 add_alias(alias, type, val)
972 if (naliases >= nslots)
977 ai.name = estrdup(alias);
978 onaliases = naliases;
980 aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
981 sizeof(ai), aliascmp);
983 (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
988 if (onaliases == naliases) {
989 (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
998 * Searches for the named alias of the specified type.
1001 find_alias(alias, type)
1010 return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
1011 sizeof(ai), aliascmp));
1015 * Allocates more space for the aliases list.
1021 nslots += MOREALIASES;
1022 aliases = (aliasinfo *) erealloc3(aliases, nslots, sizeof(aliasinfo));
1026 * Lists the contents of the aliases list.
1033 for (n = 0; n < naliases; n++) {
1034 if (aliases[n].val == -1)
1037 switch (aliases[n].type) {
1039 (void) puts("HOST_ALIAS");
1043 (void) puts("CMND_ALIAS");
1047 (void) puts("USER_ALIAS");
1051 (void) puts("RUNAS_ALIAS");
1054 (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
1059 * Lists the contents of cm_list and ga_list for `sudo -l'.
1066 struct generic_alias *ga, key;
1068 (void) printf("User %s may run the following commands on this host:\n",
1070 for (count = 0; count < cm_list_len; count++) {
1072 /* Print the runas list. */
1073 (void) fputs(" ", stdout);
1074 if (cm_list[count].runas) {
1075 (void) putchar('(');
1076 p = strtok(cm_list[count].runas, ", ");
1078 if (p != cm_list[count].runas)
1079 (void) fputs(", ", stdout);
1082 key.type = RUNAS_ALIAS;
1083 if ((ga = (struct generic_alias *) lfind((VOID *) &key,
1084 (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
1085 (void) fputs(ga->entries, stdout);
1087 (void) fputs(p, stdout);
1088 } while ((p = strtok(NULL, ", ")));
1089 (void) fputs(") ", stdout);
1091 (void) printf("(%s) ", def_runas_default);
1094 /* Is execve(2) disabled? */
1095 if (cm_list[count].noexecve == TRUE && !def_noexec)
1096 (void) fputs("NOEXEC: ", stdout);
1097 else if (cm_list[count].noexecve == FALSE && def_noexec)
1098 (void) fputs("EXEC: ", stdout);
1100 /* Is a password required? */
1101 if (cm_list[count].nopasswd == TRUE && def_authenticate)
1102 (void) fputs("NOPASSWD: ", stdout);
1103 else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
1104 (void) fputs("PASSWD: ", stdout);
1106 /* Is setenv enabled? */
1107 if (cm_list[count].setenv == TRUE && !def_setenv)
1108 (void) fputs("SETENV: ", stdout);
1109 else if (cm_list[count].setenv == FALSE && def_setenv)
1110 (void) fputs("NOSETENV: ", stdout);
1112 /* Print the actual command or expanded Cmnd_Alias. */
1113 key.alias = cm_list[count].cmnd;
1114 key.type = CMND_ALIAS;
1115 if ((ga = (struct generic_alias *) lfind((VOID *) &key,
1116 (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
1117 (void) puts(ga->entries);
1119 (void) puts(cm_list[count].cmnd);
1122 /* Be nice and free up space now that we are done. */
1123 for (count = 0; count < ga_list_len; count++) {
1124 efree(ga_list[count].alias);
1125 efree(ga_list[count].entries);
1130 for (count = 0; count < cm_list_len; count++) {
1131 efree(cm_list[count].runas);
1132 efree(cm_list[count].cmnd);
1141 * Appends a source string to the destination, optionally prefixing a separator.
1144 append(src, dstp, dst_len, dst_size, separator)
1146 size_t *dst_len, *dst_size;
1149 size_t src_len = strlen(src);
1153 * Only add the separator if there is something to separate from.
1154 * If the last char is a '!', don't apply the separator (XXX).
1156 if (separator && dst && dst[*dst_len - 1] != '!')
1157 src_len += strlen(separator);
1161 /* Assumes dst will be NULL if not set. */
1163 dst = (char *) emalloc(BUFSIZ);
1170 /* Allocate more space if necessary. */
1171 if (*dst_size <= *dst_len + src_len) {
1172 while (*dst_size <= *dst_len + src_len)
1173 *dst_size += BUFSIZ;
1175 dst = (char *) erealloc(dst, *dst_size);
1179 /* Copy src -> dst adding a separator if appropriate and adjust len. */
1181 (void) strlcat(dst, separator, *dst_size);
1182 (void) strlcat(dst, src, *dst_size);
1183 *dst_len += src_len;
1187 * Frees up space used by the aliases list and resets the associated counters.
1195 for (n = 0; n < naliases; n++)
1196 efree(aliases[n].name);
1200 naliases = nslots = 0;
1204 * Increments ga_list_len, allocating more space as necessary.
1210 if (++ga_list_len >= ga_list_size) {
1211 while ((ga_list_size += STACKINCREMENT) < ga_list_len)
1213 ga_list = (struct generic_alias *)
1214 erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
1217 ga_list[ga_list_len - 1].entries = NULL;
1221 * Increments cm_list_len, allocating more space as necessary.
1227 if (++cm_list_len >= cm_list_size) {
1228 while ((cm_list_size += STACKINCREMENT) < cm_list_len)
1230 if (cm_list == NULL)
1231 cm_list_len = 0; /* start at 0 since it is a subscript */
1232 cm_list = (struct command_match *)
1233 erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
1236 cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
1237 cm_list[cm_list_len].nopasswd = FALSE;
1238 cm_list[cm_list_len].noexecve = FALSE;
1239 cm_list[cm_list_len].setenv = FALSE;
1243 * Frees up spaced used by a previous parser run and allocates new space
1244 * for various data structures.
1250 /* Free up old data structures if we run the parser more than once. */
1255 parse_error = FALSE;
1261 /* Allocate space for the matching stack. */
1262 stacksize = STACKINCREMENT;
1263 match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
1265 /* Allocate space for the match list (for `sudo -l'). */
1266 if (printmatches == TRUE)
1267 expand_match_list();