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 */
69 #include "emul/search.h"
70 #endif /* HAVE_LSEARCH */
73 __unused static const char rcsid[] = "$Sudo: parse.yacc,v 1.204.2.13 2008/02/27 20:34:42 millert Exp $";
77 * We must define SIZE_MAX for yacc's skeleton.c.
78 * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
79 * could be signed (as it is on SunOS 4.x).
83 # define SIZE_MAX SIZE_T_MAX
85 # define SIZE_MAX INT_MAX
86 # endif /* SIZE_T_MAX */
92 extern int sudolineno, parse_error;
94 int clearaliases = TRUE;
95 int printmatches = FALSE;
99 int used_runas = FALSE;
107 #define RUNAS_ALIAS 4
109 #define SETMATCH(_var, _val) do { \
110 if ((_var) == UNSPEC || (_val) != NOMATCH) \
114 #define SETNMATCH(_var, _val) do { \
115 if ((_val) != NOMATCH) \
117 else if ((_var) == UNSPEC) \
121 #define SETENV_RESET \
122 if (setenv_ok == IMPLIED) setenv_ok = def_setenv ? TRUE : UNSPEC
125 * The matching stack, initial space allocated in init_parser().
127 struct matchstack *match;
128 int top = 0, stacksize = 0;
132 if (top >= stacksize) { \
133 while ((stacksize += STACKINCREMENT) < top); \
134 match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
136 match[top].user = UNSPEC; \
137 match[top].cmnd = UNSPEC; \
138 match[top].host = UNSPEC; \
139 match[top].runas = UNSPEC; \
140 match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
141 match[top].noexec = def_noexec ? TRUE : UNSPEC; \
142 match[top].setenv = def_setenv ? TRUE : UNSPEC; \
143 match[top].role = NULL; \
144 match[top].type = NULL; \
150 if (top >= stacksize) { \
151 while ((stacksize += STACKINCREMENT) < top); \
152 match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
154 match[top].user = match[top-1].user; \
155 match[top].cmnd = match[top-1].cmnd; \
156 match[top].host = match[top-1].host; \
157 match[top].runas = match[top-1].runas; \
158 match[top].nopass = match[top-1].nopass; \
159 match[top].noexec = match[top-1].noexec; \
160 match[top].setenv = match[top-1].setenv; \
161 match[top].role = estrdup(match[top-1].role); \
162 match[top].type = estrdup(match[top-1].type); \
169 yyerror("matching stack underflow"); \
171 efree(match[top-1].role); \
172 efree(match[top-1].type); \
179 * For testing if foo_matches variable was set to TRUE or FALSE
181 #define MATCHED(_v) ((_v) >= 0)
184 * Shortcuts for append()
186 #define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
187 &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
189 #define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
190 &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
192 #define append_role(s, p) append(s, &cm_list[cm_list_len].role, \
193 &cm_list[cm_list_len].role_len, &cm_list[cm_list_len].role_size, p)
195 #define append_type(s, p) append(s, &cm_list[cm_list_len].type, \
196 &cm_list[cm_list_len].type_len, &cm_list[cm_list_len].type_size, p)
198 #define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
199 &ga_list[ga_list_len-1].entries_len, \
200 &ga_list[ga_list_len-1].entries_size, p)
203 * The stack for printmatches. A list of allowed commands for the user.
205 static struct command_match *cm_list = NULL;
206 static size_t cm_list_len = 0, cm_list_size = 0;
209 * List of Cmnd_Aliases and expansions for `sudo -l'
211 static int in_alias = FALSE;
212 static size_t ga_list_len = 0, ga_list_size = 0;
213 static struct generic_alias *ga_list = NULL;
216 * Does this Defaults list pertain to this user?
218 static int defaults_matches = FALSE;
223 static int add_alias __P((char *, int, int));
224 static void append __P((char *, char **, size_t *, size_t *, char *));
225 static void expand_ga_list __P((void));
226 static void expand_match_list __P((void));
227 static aliasinfo *find_alias __P((char *, int));
228 static void more_aliases __P((void));
229 void init_parser __P((void));
230 void yyerror __P((char *));
236 /* Save the line the first error occurred on. */
237 if (errorlineno == -1)
238 errorlineno = sudolineno ? sudolineno - 1 : 0;
241 (void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s,
242 sudolineno ? sudolineno - 1 : 0);
244 (void) fprintf(stderr, "<*> ");
254 struct sudo_command command;
256 struct selinux_info seinfo;
259 %start file /* special start symbol */
260 %token <command> COMMAND /* absolute pathname w/ optional args */
261 %token <string> ALIAS /* an UPPERCASE alias name */
262 %token <string> DEFVAR /* a Defaults variable name */
263 %token <string> NTWKADDR /* w.x.y.z or ipv6 address */
264 %token <string> NETGROUP /* a netgroup (+NAME) */
265 %token <string> USERGROUP /* a usergroup (%NAME) */
266 %token <string> WORD /* a word */
267 %token <tok> DEFAULTS /* Defaults entry */
268 %token <tok> DEFAULTS_HOST /* Host-specific defaults entry */
269 %token <tok> DEFAULTS_USER /* User-specific defaults entry */
270 %token <tok> DEFAULTS_RUNAS /* Runas-specific defaults entry */
271 %token <tok> RUNAS /* ( runas_list ) */
272 %token <tok> NOPASSWD /* no passwd req for command */
273 %token <tok> PASSWD /* passwd req for command (default) */
274 %token <tok> NOEXEC /* preload dummy execve() for cmnd */
275 %token <tok> EXEC /* don't preload dummy execve() */
276 %token <tok> SETENV /* user may set environment for cmnd */
277 %token <tok> NOSETENV /* user may not set environment */
278 %token <tok> ALL /* ALL keyword */
279 %token <tok> COMMENT /* comment and/or carriage return */
280 %token <tok> HOSTALIAS /* Host_Alias keyword */
281 %token <tok> CMNDALIAS /* Cmnd_Alias keyword */
282 %token <tok> USERALIAS /* User_Alias keyword */
283 %token <tok> RUNASALIAS /* Runas_Alias keyword */
284 %token <tok> ':' '=' ',' '!' '+' '-' /* union member tokens */
286 %token <tok> TYPE /* SELinux type */
287 %token <tok> ROLE /* SELinux role */
290 * NOTE: these are not true booleans as there are actually 4 possible values:
291 * 1) TRUE (positive match)
292 * 0) FALSE (negative match due to a '!' somewhere)
293 * -1) NOMATCH (don't change the value of *_matches)
294 * -2) UNSPEC (uninitialized value)
298 %type <BOOLEAN> runasuser
299 %type <BOOLEAN> oprunasuser
300 %type <BOOLEAN> runaslist
302 %type <seinfo> selinux
303 %type <string> rolespec
304 %type <string> typespec
316 | { push; } userlist privileges {
317 while (top && user_matches != TRUE)
320 | USERALIAS useraliases
322 | HOSTALIAS hostaliases
324 | CMNDALIAS cmndaliases
326 | RUNASALIAS runasaliases
332 defaults_line : defaults_type defaults_list
335 defaults_type : DEFAULTS {
336 defaults_matches = TRUE;
338 | DEFAULTS_USER { push; } userlist {
339 defaults_matches = user_matches;
342 | DEFAULTS_RUNAS { push; } runaslist {
343 defaults_matches = $3 == TRUE;
346 | DEFAULTS_HOST { push; } hostlist {
347 defaults_matches = host_matches;
352 defaults_list : defaults_entry
353 | defaults_entry ',' defaults_list
356 defaults_entry : DEFVAR {
357 if (defaults_matches == TRUE &&
358 !set_default($1, NULL, TRUE)) {
365 if (defaults_matches == TRUE &&
366 !set_default($2, NULL, FALSE)) {
373 if (defaults_matches == TRUE &&
374 !set_default($1, $3, TRUE)) {
382 if (defaults_matches == TRUE &&
383 !set_default($1, $3, '+')) {
391 if (defaults_matches == TRUE &&
392 !set_default($1, $3, '-')) {
401 privileges : privilege
402 | privileges ':' privilege
405 privilege : hostlist '=' cmndspeclist {
407 * We already did a push if necessary in
408 * cmndspec so just reset some values so
409 * the next 'privilege' gets a clean slate.
411 host_matches = UNSPEC;
412 runas_matches = UNSPEC;
413 no_passwd = def_authenticate ? UNSPEC : TRUE;
414 no_execve = def_noexec ? TRUE : UNSPEC;
415 setenv_ok = def_setenv ? TRUE : UNSPEC;
417 efree(match[top-1].role);
418 match[top-1].role = NULL;
419 efree(match[top-1].type);
420 match[top-1].type = NULL;
426 SETMATCH(host_matches, $1);
429 SETNMATCH(host_matches, $2);
437 if (addr_matches($1))
445 if (netgr_matches($1, user_host, user_shost, NULL))
453 if (hostname_matches(user_shost, user_host, $1) == 0)
460 aliasinfo *aip = find_alias($1, HOST_ALIAS);
463 /* could be an all-caps hostname */
466 else if (strcasecmp(user_shost, $1) == 0)
470 (void) fprintf(stderr,
471 "%s: undeclared Host_Alias `%s' referenced near line %d\n",
472 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
484 cmndspeclist : cmndspec
485 | cmndspeclist ',' cmndspec
488 cmndspec : { SETENV_RESET; } runasspec selinux cmndtag opcmnd {
490 /* Replace inherited role/type as needed. */
491 if ($3.role != NULL) {
492 efree(match[top-1].role);
493 match[top-1].role = $3.role;
495 if ($3.type != NULL) {
496 efree(match[top-1].type);
497 match[top-1].type = $3.type;
501 * Push the entry onto the stack if it is worth
502 * saving and reset cmnd_matches for next cmnd.
504 * We need to save at least one entry on
505 * the stack so sudoers_lookup() can tell that
506 * the user was listed in sudoers. Also, we
507 * need to be able to tell whether or not a
508 * user was listed for this specific host.
510 * If keepall is set and the user matches then
511 * we need to keep entries around too...
513 if (MATCHED(user_matches) &&
514 MATCHED(host_matches) &&
515 MATCHED(cmnd_matches) &&
516 MATCHED(runas_matches))
518 else if (MATCHED(user_matches) && (top == 1 ||
519 (top == 2 && MATCHED(host_matches) &&
520 !MATCHED(match[0].host))))
522 else if (user_matches == TRUE && keepall)
525 cmnd_matches = UNSPEC;
530 SETMATCH(cmnd_matches, $1);
533 if (printmatches == TRUE) {
534 if (in_alias == TRUE)
535 append_entries("!", ", ");
536 else if (host_matches == TRUE &&
537 user_matches == TRUE)
538 append_cmnd("!", NULL);
541 SETNMATCH(cmnd_matches, $3);
545 rolespec : ROLE '=' WORD {
547 if (printmatches == TRUE && host_matches == TRUE &&
548 user_matches == TRUE && runas_matches == TRUE)
549 append_role($3, NULL);
554 #endif /* HAVE_SELINUX */
558 typespec : TYPE '=' WORD {
560 if (printmatches == TRUE && host_matches == TRUE &&
561 user_matches == TRUE && runas_matches == TRUE)
562 append_type($3, NULL);
567 #endif /* HAVE_SELINUX */
571 selinux : /* empty */ {
573 if (printmatches == TRUE && host_matches == TRUE &&
574 user_matches == TRUE && runas_matches == TRUE) {
576 cm_list[cm_list_len].role =
577 estrdup(cm_list[cm_list_len-1].role);
578 cm_list[cm_list_len].role_len =
579 cm_list[cm_list_len-1].role_len;
580 cm_list[cm_list_len].role_size =
581 cm_list[cm_list_len-1].role_len + 1;
583 cm_list[cm_list_len].type =
584 estrdup(cm_list[cm_list_len-1].type);
585 cm_list[cm_list_len].type_len =
586 cm_list[cm_list_len-1].type_len;
587 cm_list[cm_list_len].type_size =
588 cm_list[cm_list_len-1].type_len + 1;
590 #endif /* HAVE_SELINUX */
596 if (printmatches == TRUE && host_matches == TRUE &&
597 user_matches == TRUE && runas_matches == TRUE) {
599 cm_list[cm_list_len].type =
600 estrdup(cm_list[cm_list_len-1].type);
601 cm_list[cm_list_len].type_len =
602 cm_list[cm_list_len-1].type_len;
603 cm_list[cm_list_len].type_size =
604 cm_list[cm_list_len-1].type_len + 1;
606 #endif /* HAVE_SELINUX */
612 if (printmatches == TRUE && host_matches == TRUE &&
613 user_matches == TRUE && runas_matches == TRUE) {
615 cm_list[cm_list_len].role =
616 estrdup(cm_list[cm_list_len-1].role);
617 cm_list[cm_list_len].role_len =
618 cm_list[cm_list_len-1].role_len;
619 cm_list[cm_list_len].role_size =
620 cm_list[cm_list_len-1].role_len + 1;
622 #endif /* HAVE_SELINUX */
626 | rolespec typespec {
630 | typespec rolespec {
636 runasspec : /* empty */ {
637 if (printmatches == TRUE && host_matches == TRUE &&
638 user_matches == TRUE) {
639 if (runas_matches == UNSPEC) {
640 cm_list[cm_list_len].runas_len = 0;
642 /* Inherit runas data. */
643 cm_list[cm_list_len].runas =
644 estrdup(cm_list[cm_list_len-1].runas);
645 cm_list[cm_list_len].runas_len =
646 cm_list[cm_list_len-1].runas_len;
647 cm_list[cm_list_len].runas_size =
648 cm_list[cm_list_len-1].runas_len + 1;
652 * If this is the first entry in a command list
653 * then check against default runas user.
655 if (runas_matches == UNSPEC) {
656 runas_matches = userpw_matches(def_runas_default,
657 *user_runas, runas_pw) ? TRUE : NOMATCH;
665 runaslist : oprunasuser { ; }
666 | runaslist ',' oprunasuser {
667 /* Later entries override earlier ones. */
675 oprunasuser : runasuser { ; }
677 if (printmatches == TRUE) {
678 if (in_alias == TRUE)
679 append_entries("!", ", ");
680 else if (host_matches == TRUE &&
681 user_matches == TRUE)
682 append_runas("!", ", ");
685 /* Set $$ to the negation of runasuser */
686 $$ = ($3 == NOMATCH ? NOMATCH : ! $3);
691 if (printmatches == TRUE) {
692 if (in_alias == TRUE)
693 append_entries($1, ", ");
694 else if (host_matches == TRUE &&
695 user_matches == TRUE)
696 append_runas($1, ", ");
698 if (userpw_matches($1, *user_runas, runas_pw))
706 if (printmatches == TRUE) {
707 if (in_alias == TRUE)
708 append_entries($1, ", ");
709 else if (host_matches == TRUE &&
710 user_matches == TRUE)
711 append_runas($1, ", ");
713 if (usergr_matches($1, *user_runas, runas_pw))
721 if (printmatches == TRUE) {
722 if (in_alias == TRUE)
723 append_entries($1, ", ");
724 else if (host_matches == TRUE &&
725 user_matches == TRUE)
726 append_runas($1, ", ");
728 if (netgr_matches($1, NULL, NULL, *user_runas))
736 aliasinfo *aip = find_alias($1, RUNAS_ALIAS);
738 if (printmatches == TRUE) {
739 if (in_alias == TRUE)
740 append_entries($1, ", ");
741 else if (host_matches == TRUE &&
742 user_matches == TRUE)
743 append_runas($1, ", ");
745 /* could be an all-caps username */
748 else if (strcmp($1, *user_runas) == 0)
752 (void) fprintf(stderr,
753 "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
754 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
766 if (printmatches == TRUE) {
767 if (in_alias == TRUE)
768 append_entries("ALL", ", ");
769 else if (host_matches == TRUE &&
770 user_matches == TRUE)
771 append_runas("ALL", ", ");
777 cmndtag : /* empty */ {
778 /* Inherit {NO,}{PASSWD,EXEC,SETENV} status. */
779 if (printmatches == TRUE && host_matches == TRUE &&
780 user_matches == TRUE) {
781 if (no_passwd == TRUE)
782 cm_list[cm_list_len].nopasswd = TRUE;
784 cm_list[cm_list_len].nopasswd = FALSE;
785 if (no_execve == TRUE)
786 cm_list[cm_list_len].noexecve = TRUE;
788 cm_list[cm_list_len].noexecve = FALSE;
789 if (setenv_ok == TRUE)
790 cm_list[cm_list_len].setenv = TRUE;
792 cm_list[cm_list_len].setenv = FALSE;
797 if (printmatches == TRUE && host_matches == TRUE &&
798 user_matches == TRUE)
799 cm_list[cm_list_len].nopasswd = TRUE;
803 if (printmatches == TRUE && host_matches == TRUE &&
804 user_matches == TRUE)
805 cm_list[cm_list_len].nopasswd = FALSE;
809 if (printmatches == TRUE && host_matches == TRUE &&
810 user_matches == TRUE)
811 cm_list[cm_list_len].noexecve = TRUE;
815 if (printmatches == TRUE && host_matches == TRUE &&
816 user_matches == TRUE)
817 cm_list[cm_list_len].noexecve = FALSE;
821 if (printmatches == TRUE && host_matches == TRUE &&
822 user_matches == TRUE)
823 cm_list[cm_list_len].setenv = TRUE;
827 if (printmatches == TRUE && host_matches == TRUE &&
828 user_matches == TRUE)
829 cm_list[cm_list_len].setenv = FALSE;
834 if (printmatches == TRUE) {
835 if (in_alias == TRUE)
836 append_entries("ALL", ", ");
837 else if (host_matches == TRUE &&
838 user_matches == TRUE) {
839 append_cmnd("ALL", NULL);
843 /* sudo "ALL" implies the SETENV tag */
844 if (setenv_ok == UNSPEC)
854 if (printmatches == TRUE) {
855 if (in_alias == TRUE)
856 append_entries($1, ", ");
857 else if (host_matches == TRUE &&
858 user_matches == TRUE) {
859 append_cmnd($1, NULL);
864 if ((aip = find_alias($1, CMND_ALIAS)))
868 (void) fprintf(stderr,
869 "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
870 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
881 if (printmatches == TRUE) {
882 if (in_alias == TRUE) {
883 append_entries($1.cmnd, ", ");
885 append_entries($1.args, " ");
887 if (host_matches == TRUE &&
888 user_matches == TRUE) {
889 append_cmnd($1.cmnd, NULL);
891 append_cmnd($1.args, " ");
896 if (command_matches($1.cmnd, $1.args))
906 hostaliases : hostalias
907 | hostaliases ':' hostalias
910 hostalias : ALIAS { push; } '=' hostlist {
911 if ((MATCHED(host_matches) || pedantic) &&
912 !add_alias($1, HOST_ALIAS, host_matches)) {
921 | hostlist ',' ophost
924 cmndaliases : cmndalias
925 | cmndaliases ':' cmndalias
930 if (printmatches == TRUE) {
932 /* Allocate space for ga_list if necessary. */
934 ga_list[ga_list_len-1].type = CMND_ALIAS;
935 ga_list[ga_list_len-1].alias = estrdup($1);
938 if ((MATCHED(cmnd_matches) || pedantic) &&
939 !add_alias($1, CMND_ALIAS, cmnd_matches)) {
946 if (printmatches == TRUE)
951 cmndlist : opcmnd { ; }
952 | cmndlist ',' opcmnd
955 runasaliases : runasalias
956 | runasaliases ':' runasalias
960 if (printmatches == TRUE) {
962 /* Allocate space for ga_list if necessary. */
964 ga_list[ga_list_len-1].type = RUNAS_ALIAS;
965 ga_list[ga_list_len-1].alias = estrdup($1);
968 if (($4 != NOMATCH || pedantic) &&
969 !add_alias($1, RUNAS_ALIAS, $4)) {
975 if (printmatches == TRUE)
980 useraliases : useralias
981 | useraliases ':' useralias
984 useralias : ALIAS { push; } '=' userlist {
985 if ((MATCHED(user_matches) || pedantic) &&
986 !add_alias($1, USER_ALIAS, user_matches)) {
996 | userlist ',' opuser
1000 SETMATCH(user_matches, $1);
1003 SETNMATCH(user_matches, $2);
1008 if (userpw_matches($1, user_name, sudo_user.pw))
1015 if (usergr_matches($1, user_name, sudo_user.pw))
1022 if (netgr_matches($1, NULL, NULL, user_name))
1029 aliasinfo *aip = find_alias($1, USER_ALIAS);
1031 /* could be an all-caps username */
1034 else if (strcmp($1, user_name) == 0)
1038 (void) fprintf(stderr,
1039 "%s: undeclared User_Alias `%s' referenced near line %d\n",
1040 (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
1057 #define MOREALIASES (32)
1058 aliasinfo *aliases = NULL;
1059 size_t naliases = 0;
1064 * Compare two aliasinfo structures, strcmp() style.
1065 * Note that we do *not* compare their values.
1069 const VOID *a1, *a2;
1072 aliasinfo *ai1, *ai2;
1074 ai1 = (aliasinfo *) a1;
1075 ai2 = (aliasinfo *) a2;
1076 if ((r = strcmp(ai1->name, ai2->name)) == 0)
1077 r = ai1->type - ai2->type;
1083 * Compare two generic_alias structures, strcmp() style.
1086 genaliascmp(entry, key)
1087 const VOID *entry, *key;
1090 struct generic_alias *ga1, *ga2;
1092 ga1 = (struct generic_alias *) key;
1093 ga2 = (struct generic_alias *) entry;
1094 if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
1095 r = ga1->type - ga2->type;
1102 * Adds the named alias of the specified type to the aliases list.
1105 add_alias(alias, type, val)
1114 if (naliases >= nslots)
1119 ai.name = estrdup(alias);
1120 onaliases = naliases;
1122 aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
1123 sizeof(ai), aliascmp);
1125 (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
1130 if (onaliases == naliases) {
1131 (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
1140 * Searches for the named alias of the specified type.
1143 find_alias(alias, type)
1152 return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
1153 sizeof(ai), aliascmp));
1157 * Allocates more space for the aliases list.
1163 nslots += MOREALIASES;
1164 aliases = (aliasinfo *) erealloc3(aliases, nslots, sizeof(aliasinfo));
1168 * Lists the contents of the aliases list.
1175 for (n = 0; n < naliases; n++) {
1176 if (aliases[n].val == -1)
1179 switch (aliases[n].type) {
1181 (void) puts("HOST_ALIAS");
1185 (void) puts("CMND_ALIAS");
1189 (void) puts("USER_ALIAS");
1193 (void) puts("RUNAS_ALIAS");
1196 (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
1201 * Lists the contents of cm_list and ga_list for `sudo -l'.
1208 struct generic_alias *ga, key;
1210 (void) printf("User %s may run the following commands on this host:\n",
1212 for (count = 0; count < cm_list_len; count++) {
1214 /* Print the runas list. */
1215 (void) fputs(" ", stdout);
1216 if (cm_list[count].runas) {
1217 (void) putchar('(');
1218 p = strtok(cm_list[count].runas, ", ");
1220 if (p != cm_list[count].runas)
1221 (void) fputs(", ", stdout);
1224 key.type = RUNAS_ALIAS;
1225 if ((ga = (struct generic_alias *) lfind((VOID *) &key,
1226 (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
1227 (void) fputs(ga->entries, stdout);
1229 (void) fputs(p, stdout);
1230 } while ((p = strtok(NULL, ", ")));
1231 (void) fputs(") ", stdout);
1233 (void) printf("(%s) ", def_runas_default);
1237 /* SELinux role and type */
1238 if (cm_list[count].role != NULL)
1239 (void) printf("ROLE=%s ", cm_list[count].role);
1240 if (cm_list[count].type != NULL)
1241 (void) printf("TYPE=%s ", cm_list[count].type);
1244 /* Is execve(2) disabled? */
1245 if (cm_list[count].noexecve == TRUE && !def_noexec)
1246 (void) fputs("NOEXEC: ", stdout);
1247 else if (cm_list[count].noexecve == FALSE && def_noexec)
1248 (void) fputs("EXEC: ", stdout);
1250 /* Is a password required? */
1251 if (cm_list[count].nopasswd == TRUE && def_authenticate)
1252 (void) fputs("NOPASSWD: ", stdout);
1253 else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
1254 (void) fputs("PASSWD: ", stdout);
1256 /* Is setenv enabled? */
1257 if (cm_list[count].setenv == TRUE && !def_setenv)
1258 (void) fputs("SETENV: ", stdout);
1259 else if (cm_list[count].setenv == FALSE && def_setenv)
1260 (void) fputs("NOSETENV: ", stdout);
1262 /* Print the actual command or expanded Cmnd_Alias. */
1263 key.alias = cm_list[count].cmnd;
1264 key.type = CMND_ALIAS;
1265 if ((ga = (struct generic_alias *) lfind((VOID *) &key,
1266 (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
1267 (void) puts(ga->entries);
1269 (void) puts(cm_list[count].cmnd);
1272 /* Be nice and free up space now that we are done. */
1273 for (count = 0; count < ga_list_len; count++) {
1274 efree(ga_list[count].alias);
1275 efree(ga_list[count].entries);
1280 for (count = 0; count < cm_list_len; count++) {
1281 efree(cm_list[count].runas);
1282 efree(cm_list[count].cmnd);
1283 efree(cm_list[count].role);
1284 efree(cm_list[count].type);
1293 * Appends a source string to the destination, optionally prefixing a separator.
1296 append(src, dstp, dst_len, dst_size, separator)
1298 size_t *dst_len, *dst_size;
1301 size_t src_len = strlen(src);
1305 * Only add the separator if there is something to separate from.
1306 * If the last char is a '!', don't apply the separator (XXX).
1308 if (separator && dst && dst[*dst_len - 1] != '!')
1309 src_len += strlen(separator);
1313 /* Assumes dst will be NULL if not set. */
1315 dst = (char *) emalloc(BUFSIZ);
1322 /* Allocate more space if necessary. */
1323 if (*dst_size <= *dst_len + src_len) {
1324 while (*dst_size <= *dst_len + src_len)
1325 *dst_size += BUFSIZ;
1327 dst = (char *) erealloc(dst, *dst_size);
1331 /* Copy src -> dst adding a separator if appropriate and adjust len. */
1333 (void) strlcat(dst, separator, *dst_size);
1334 (void) strlcat(dst, src, *dst_size);
1335 *dst_len += src_len;
1339 * Frees up space used by the aliases list and resets the associated counters.
1347 for (n = 0; n < naliases; n++)
1348 efree(aliases[n].name);
1352 naliases = nslots = 0;
1356 * Increments ga_list_len, allocating more space as necessary.
1362 if (++ga_list_len >= ga_list_size) {
1363 while ((ga_list_size += STACKINCREMENT) < ga_list_len)
1365 ga_list = (struct generic_alias *)
1366 erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
1369 ga_list[ga_list_len - 1].entries = NULL;
1373 * Increments cm_list_len, allocating more space as necessary.
1379 if (++cm_list_len >= cm_list_size) {
1380 while ((cm_list_size += STACKINCREMENT) < cm_list_len)
1382 if (cm_list == NULL)
1383 cm_list_len = 0; /* start at 0 since it is a subscript */
1384 cm_list = (struct command_match *)
1385 erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
1388 cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
1389 cm_list[cm_list_len].type = cm_list[cm_list_len].role = NULL;
1390 cm_list[cm_list_len].nopasswd = FALSE;
1391 cm_list[cm_list_len].noexecve = FALSE;
1392 cm_list[cm_list_len].setenv = FALSE;
1396 * Frees up spaced used by a previous parser run and allocates new space
1397 * for various data structures.
1403 /* Free up old data structures if we run the parser more than once. */
1408 parse_error = FALSE;
1414 /* Allocate space for the matching stack. */
1415 stacksize = STACKINCREMENT;
1416 match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
1418 /* Allocate space for the match list (for `sudo -l'). */
1419 if (printmatches == TRUE)
1420 expand_match_list();