[BACK]Return to parse.yacc CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/parse.yacc, Revision 1.20

1.1       millert     1: %{
                      2: /*
1.12      millert     3:  * Copyright (c) 1996, 1998-2004, 2007
                      4:  *     Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     5:  *
1.10      millert     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.
1.1       millert     9:  *
1.10      millert    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.
1.1       millert    17:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     18:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.9       millert    19:  *
                     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.
1.1       millert    23:  */
                     24:
                     25: /*
                     26:  * XXX - the whole opFOO naming thing is somewhat bogus.
                     27:  *
                     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.
                     31:  */
                     32:
1.12      millert    33: #include <config.h>
1.6       millert    34:
                     35: #include <sys/types.h>
                     36: #include <sys/param.h>
1.1       millert    37: #include <stdio.h>
                     38: #ifdef STDC_HEADERS
1.6       millert    39: # include <stdlib.h>
                     40: # include <stddef.h>
                     41: #else
                     42: # ifdef HAVE_STDLIB_H
                     43: #  include <stdlib.h>
                     44: # endif
1.1       millert    45: #endif /* STDC_HEADERS */
1.6       millert    46: #ifdef HAVE_STRING_H
                     47: # include <string.h>
                     48: #else
                     49: # ifdef HAVE_STRINGS_H
                     50: #  include <strings.h>
                     51: # endif
                     52: #endif /* HAVE_STRING_H */
1.1       millert    53: #ifdef HAVE_UNISTD_H
1.6       millert    54: # include <unistd.h>
1.1       millert    55: #endif /* HAVE_UNISTD_H */
                     56: #include <pwd.h>
                     57: #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
1.6       millert    58: # include <alloca.h>
1.1       millert    59: #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
                     60: #ifdef HAVE_LSEARCH
1.6       millert    61: # include <search.h>
1.1       millert    62: #endif /* HAVE_LSEARCH */
1.20    ! millert    63: #include <limits.h>
1.1       millert    64:
                     65: #include "sudo.h"
                     66: #include "parse.h"
                     67:
                     68: #ifndef HAVE_LSEARCH
                     69: #include "emul/search.h"
                     70: #endif /* HAVE_LSEARCH */
                     71:
                     72: #ifndef lint
1.20    ! millert    73: __unused static const char rcsid[] = "$Sudo: parse.yacc,v 1.204.2.10 2008/01/16 23:20:53 millert Exp $";
1.1       millert    74: #endif /* lint */
1.20    ! millert    75:
        !            76: /*
        !            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).
        !            80:  */
        !            81: #ifndef SIZE_MAX
        !            82: # ifdef SIZE_T_MAX
        !            83: #  define SIZE_MAX     SIZE_T_MAX
        !            84: # else
        !            85: #  define SIZE_MAX     INT_MAX
        !            86: # endif /* SIZE_T_MAX */
        !            87: #endif /* SIZE_MAX */
1.1       millert    88:
                     89: /*
                     90:  * Globals
                     91:  */
                     92: extern int sudolineno, parse_error;
                     93: int errorlineno = -1;
                     94: int clearaliases = TRUE;
                     95: int printmatches = FALSE;
                     96: int pedantic = FALSE;
1.3       millert    97: int keepall = FALSE;
1.6       millert    98: int quiet = FALSE;
1.10      millert    99: int used_runas = FALSE;
1.1       millert   100:
                    101: /*
                    102:  * Alias types
                    103:  */
                    104: #define HOST_ALIAS              1
                    105: #define CMND_ALIAS              2
                    106: #define USER_ALIAS              3
                    107: #define RUNAS_ALIAS             4
                    108:
1.10      millert   109: #define SETMATCH(_var, _val)   do { \
                    110:        if ((_var) == UNSPEC || (_val) != NOMATCH) \
                    111:            (_var) = (_val); \
                    112: } while (0)
                    113:
                    114: #define SETNMATCH(_var, _val)  do { \
                    115:        if ((_val) != NOMATCH) \
                    116:            (_var) = ! (_val); \
                    117:        else if ((_var) == UNSPEC) \
                    118:            (_var) = NOMATCH; \
                    119: } while (0)
                    120:
1.19      millert   121: #define        SETENV_RESET \
                    122:        if (setenv_ok == IMPLIED) setenv_ok = def_setenv ? TRUE : UNSPEC
                    123:
1.1       millert   124: /*
                    125:  * The matching stack, initial space allocated in init_parser().
                    126:  */
                    127: struct matchstack *match;
                    128: int top = 0, stacksize = 0;
                    129:
                    130: #define push \
                    131:     do { \
                    132:        if (top >= stacksize) { \
                    133:            while ((stacksize += STACKINCREMENT) < top); \
1.8       millert   134:            match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
1.1       millert   135:        } \
1.10      millert   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; \
1.12      millert   142:        match[top].setenv = def_setenv ? TRUE : UNSPEC; \
1.1       millert   143:        top++; \
                    144:     } while (0)
                    145:
                    146: #define pushcp \
                    147:     do { \
                    148:        if (top >= stacksize) { \
                    149:            while ((stacksize += STACKINCREMENT) < top); \
1.8       millert   150:            match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
1.1       millert   151:        } \
                    152:        match[top].user   = match[top-1].user; \
                    153:        match[top].cmnd   = match[top-1].cmnd; \
                    154:        match[top].host   = match[top-1].host; \
                    155:        match[top].runas  = match[top-1].runas; \
                    156:        match[top].nopass = match[top-1].nopass; \
1.10      millert   157:        match[top].noexec = match[top-1].noexec; \
1.12      millert   158:        match[top].setenv = match[top-1].setenv; \
1.1       millert   159:        top++; \
                    160:     } while (0)
                    161:
                    162: #define pop \
1.10      millert   163:     do { \
1.1       millert   164:        if (top == 0) \
                    165:            yyerror("matching stack underflow"); \
                    166:        else \
                    167:            top--; \
1.10      millert   168:     } while (0)
                    169:
                    170:
                    171: /*
                    172:  * For testing if foo_matches variable was set to TRUE or FALSE
                    173:  */
                    174: #define        MATCHED(_v)     ((_v) >= 0)
1.1       millert   175:
                    176: /*
                    177:  * Shortcuts for append()
                    178:  */
                    179: #define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
                    180:        &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
                    181:
                    182: #define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
                    183:        &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
                    184:
                    185: #define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
                    186:        &ga_list[ga_list_len-1].entries_len, \
                    187:        &ga_list[ga_list_len-1].entries_size, p)
                    188:
                    189: /*
                    190:  * The stack for printmatches.  A list of allowed commands for the user.
                    191:  */
                    192: static struct command_match *cm_list = NULL;
                    193: static size_t cm_list_len = 0, cm_list_size = 0;
                    194:
                    195: /*
                    196:  * List of Cmnd_Aliases and expansions for `sudo -l'
                    197:  */
                    198: static int in_alias = FALSE;
                    199: static size_t ga_list_len = 0, ga_list_size = 0;
                    200: static struct generic_alias *ga_list = NULL;
                    201:
                    202: /*
                    203:  * Does this Defaults list pertain to this user?
                    204:  */
1.10      millert   205: static int defaults_matches = FALSE;
1.1       millert   206:
                    207: /*
                    208:  * Local protoypes
                    209:  */
                    210: static int  add_alias          __P((char *, int, int));
                    211: static void append             __P((char *, char **, size_t *, size_t *, char *));
                    212: static void expand_ga_list     __P((void));
                    213: static void expand_match_list  __P((void));
                    214: static aliasinfo *find_alias   __P((char *, int));
1.16      millert   215: static void more_aliases       __P((void));
1.1       millert   216:        void init_parser                __P((void));
                    217:        void yyerror            __P((char *));
                    218:
                    219: void
                    220: yyerror(s)
                    221:     char *s;
                    222: {
1.5       mpech     223:     /* Save the line the first error occurred on. */
1.1       millert   224:     if (errorlineno == -1)
                    225:        errorlineno = sudolineno ? sudolineno - 1 : 0;
1.6       millert   226:     if (s && !quiet) {
1.1       millert   227: #ifndef TRACELEXER
                    228:        (void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s,
                    229:            sudolineno ? sudolineno - 1 : 0);
                    230: #else
                    231:        (void) fprintf(stderr, "<*> ");
                    232: #endif
                    233:     }
                    234:     parse_error = TRUE;
                    235: }
                    236: %}
                    237:
                    238: %union {
                    239:     char *string;
                    240:     int BOOLEAN;
                    241:     struct sudo_command command;
                    242:     int tok;
                    243: }
                    244:
                    245: %start file                            /* special start symbol */
                    246: %token <command> COMMAND               /* absolute pathname w/ optional args */
                    247: %token <string>  ALIAS                 /* an UPPERCASE alias name */
1.6       millert   248: %token <string>         DEFVAR                 /* a Defaults variable name */
1.13      millert   249: %token <string>  NTWKADDR              /* w.x.y.z or ipv6 address */
1.1       millert   250: %token <string>  NETGROUP              /* a netgroup (+NAME) */
                    251: %token <string>  USERGROUP             /* a usergroup (%NAME) */
                    252: %token <string>  WORD                  /* a word */
                    253: %token <tok>    DEFAULTS               /* Defaults entry */
                    254: %token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
                    255: %token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
1.8       millert   256: %token <tok>    DEFAULTS_RUNAS         /* Runas-specific defaults entry */
1.1       millert   257: %token <tok>    RUNAS                  /* ( runas_list ) */
                    258: %token <tok>    NOPASSWD               /* no passwd req for command */
                    259: %token <tok>    PASSWD                 /* passwd req for command (default) */
1.10      millert   260: %token <tok>    NOEXEC                 /* preload dummy execve() for cmnd */
                    261: %token <tok>    EXEC                   /* don't preload dummy execve() */
1.12      millert   262: %token <tok>    SETENV                 /* user may set environment for cmnd */
                    263: %token <tok>    NOSETENV               /* user may not set environment */
1.1       millert   264: %token <tok>    ALL                    /* ALL keyword */
                    265: %token <tok>    COMMENT                /* comment and/or carriage return */
                    266: %token <tok>    HOSTALIAS              /* Host_Alias keyword */
                    267: %token <tok>    CMNDALIAS              /* Cmnd_Alias keyword */
                    268: %token <tok>    USERALIAS              /* User_Alias keyword */
                    269: %token <tok>    RUNASALIAS             /* Runas_Alias keyword */
1.6       millert   270: %token <tok>    ':' '=' ',' '!' '+' '-' /* union member tokens */
1.1       millert   271: %token <tok>    ERROR
                    272:
                    273: /*
1.10      millert   274:  * NOTE: these are not true booleans as there are actually 4 possible values:
1.1       millert   275:  *        1) TRUE (positive match)
                    276:  *        0) FALSE (negative match due to a '!' somewhere)
1.10      millert   277:  *       -1) NOMATCH (don't change the value of *_matches)
                    278:  *       -2) UNSPEC (uninitialized value)
1.1       millert   279:  */
                    280: %type <BOOLEAN>         cmnd
                    281: %type <BOOLEAN>         host
                    282: %type <BOOLEAN>         runasuser
1.2       millert   283: %type <BOOLEAN>         oprunasuser
                    284: %type <BOOLEAN>         runaslist
1.1       millert   285: %type <BOOLEAN>         user
                    286:
                    287: %%
                    288:
                    289: file           :       entry
                    290:                |       file entry
                    291:                ;
                    292:
                    293: entry          :       COMMENT
                    294:                            { ; }
                    295:                 |       error COMMENT
                    296:                            { yyerrok; }
                    297:                |       { push; } userlist privileges {
                    298:                            while (top && user_matches != TRUE)
                    299:                                pop;
                    300:                        }
                    301:                |       USERALIAS useraliases
                    302:                            { ; }
                    303:                |       HOSTALIAS hostaliases
                    304:                            { ; }
                    305:                |       CMNDALIAS cmndaliases
                    306:                            { ; }
                    307:                |       RUNASALIAS runasaliases
                    308:                            { ; }
                    309:                |       defaults_line
                    310:                            { ; }
                    311:                ;
                    312:
                    313: defaults_line  :       defaults_type defaults_list
1.8       millert   314:                ;
1.1       millert   315:
                    316: defaults_type  :       DEFAULTS {
                    317:                            defaults_matches = TRUE;
                    318:                        }
                    319:                |       DEFAULTS_USER { push; } userlist {
                    320:                            defaults_matches = user_matches;
                    321:                            pop;
                    322:                        }
1.8       millert   323:                |       DEFAULTS_RUNAS { push; } runaslist {
                    324:                            defaults_matches = $3 == TRUE;
                    325:                            pop;
                    326:                        }
1.1       millert   327:                |       DEFAULTS_HOST { push; } hostlist {
                    328:                            defaults_matches = host_matches;
                    329:                            pop;
                    330:                        }
                    331:                ;
                    332:
                    333: defaults_list  :       defaults_entry
                    334:                |       defaults_entry ',' defaults_list
1.8       millert   335:                ;
1.1       millert   336:
1.6       millert   337: defaults_entry :       DEFVAR {
1.4       millert   338:                            if (defaults_matches == TRUE &&
1.6       millert   339:                                !set_default($1, NULL, TRUE)) {
1.1       millert   340:                                yyerror(NULL);
                    341:                                YYERROR;
                    342:                            }
1.12      millert   343:                            efree($1);
1.1       millert   344:                        }
1.6       millert   345:                |       '!' DEFVAR {
1.4       millert   346:                            if (defaults_matches == TRUE &&
1.6       millert   347:                                !set_default($2, NULL, FALSE)) {
1.1       millert   348:                                yyerror(NULL);
                    349:                                YYERROR;
                    350:                            }
1.12      millert   351:                            efree($2);
1.1       millert   352:                        }
1.6       millert   353:                |       DEFVAR '=' WORD {
                    354:                            if (defaults_matches == TRUE &&
                    355:                                !set_default($1, $3, TRUE)) {
                    356:                                yyerror(NULL);
                    357:                                YYERROR;
                    358:                            }
1.12      millert   359:                            efree($1);
                    360:                            efree($3);
1.6       millert   361:                        }
                    362:                |       DEFVAR '+' WORD {
                    363:                            if (defaults_matches == TRUE &&
                    364:                                !set_default($1, $3, '+')) {
                    365:                                yyerror(NULL);
                    366:                                YYERROR;
                    367:                            }
1.12      millert   368:                            efree($1);
                    369:                            efree($3);
1.6       millert   370:                        }
                    371:                |       DEFVAR '-' WORD {
1.4       millert   372:                            if (defaults_matches == TRUE &&
1.6       millert   373:                                !set_default($1, $3, '-')) {
1.1       millert   374:                                yyerror(NULL);
                    375:                                YYERROR;
                    376:                            }
1.12      millert   377:                            efree($1);
                    378:                            efree($3);
1.1       millert   379:                        }
1.8       millert   380:                ;
1.1       millert   381:
                    382: privileges     :       privilege
                    383:                |       privileges ':' privilege
                    384:                ;
                    385:
                    386: privilege      :       hostlist '=' cmndspeclist {
                    387:                            /*
                    388:                             * We already did a push if necessary in
                    389:                             * cmndspec so just reset some values so
                    390:                             * the next 'privilege' gets a clean slate.
                    391:                             */
1.10      millert   392:                            host_matches = UNSPEC;
                    393:                            runas_matches = UNSPEC;
                    394:                            no_passwd = def_authenticate ? UNSPEC : TRUE;
                    395:                            no_execve = def_noexec ? TRUE : UNSPEC;
1.12      millert   396:                            setenv_ok = def_setenv ? TRUE : UNSPEC;
1.1       millert   397:                        }
                    398:                ;
                    399:
                    400: ophost         :       host {
1.10      millert   401:                            SETMATCH(host_matches, $1);
1.1       millert   402:                        }
                    403:                |       '!' host {
1.10      millert   404:                            SETNMATCH(host_matches, $2);
1.1       millert   405:                        }
1.8       millert   406:                ;
1.1       millert   407:
                    408: host           :       ALL {
                    409:                            $$ = TRUE;
                    410:                        }
                    411:                |       NTWKADDR {
                    412:                            if (addr_matches($1))
                    413:                                $$ = TRUE;
                    414:                            else
1.10      millert   415:                                $$ = NOMATCH;
1.12      millert   416:                            efree($1);
1.1       millert   417:                        }
                    418:                |       NETGROUP {
1.3       millert   419:                            if (netgr_matches($1, user_host, user_shost, NULL))
1.1       millert   420:                                $$ = TRUE;
                    421:                            else
1.10      millert   422:                                $$ = NOMATCH;
1.12      millert   423:                            efree($1);
1.1       millert   424:                        }
                    425:                |       WORD {
1.4       millert   426:                            if (hostname_matches(user_shost, user_host, $1) == 0)
1.1       millert   427:                                $$ = TRUE;
                    428:                            else
1.10      millert   429:                                $$ = NOMATCH;
1.12      millert   430:                            efree($1);
1.1       millert   431:                        }
                    432:                |       ALIAS {
                    433:                            aliasinfo *aip = find_alias($1, HOST_ALIAS);
                    434:
                    435:                            /* could be an all-caps hostname */
                    436:                            if (aip)
                    437:                                $$ = aip->val;
                    438:                            else if (strcasecmp(user_shost, $1) == 0)
                    439:                                $$ = TRUE;
                    440:                            else {
                    441:                                if (pedantic) {
                    442:                                    (void) fprintf(stderr,
                    443:                                        "%s: undeclared Host_Alias `%s' referenced near line %d\n",
                    444:                                        (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
                    445:                                    if (pedantic > 1) {
                    446:                                        yyerror(NULL);
                    447:                                        YYERROR;
                    448:                                    }
                    449:                                }
1.10      millert   450:                                $$ = NOMATCH;
1.1       millert   451:                            }
1.12      millert   452:                            efree($1);
1.1       millert   453:                        }
                    454:                ;
                    455:
                    456: cmndspeclist   :       cmndspec
                    457:                |       cmndspeclist ',' cmndspec
                    458:                ;
                    459:
1.19      millert   460: cmndspec       :       { SETENV_RESET; } runasspec cmndtag opcmnd {
1.1       millert   461:                            /*
                    462:                             * Push the entry onto the stack if it is worth
1.10      millert   463:                             * saving and reset cmnd_matches for next cmnd.
1.1       millert   464:                             *
                    465:                             * We need to save at least one entry on
                    466:                             * the stack so sudoers_lookup() can tell that
                    467:                             * the user was listed in sudoers.  Also, we
                    468:                             * need to be able to tell whether or not a
                    469:                             * user was listed for this specific host.
1.3       millert   470:                             *
                    471:                             * If keepall is set and the user matches then
                    472:                             * we need to keep entries around too...
1.1       millert   473:                             */
1.10      millert   474:                            if (MATCHED(user_matches) &&
                    475:                                MATCHED(host_matches) &&
                    476:                                MATCHED(cmnd_matches) &&
                    477:                                MATCHED(runas_matches))
1.1       millert   478:                                pushcp;
1.10      millert   479:                            else if (MATCHED(user_matches) && (top == 1 ||
                    480:                                (top == 2 && MATCHED(host_matches) &&
                    481:                                !MATCHED(match[0].host))))
1.1       millert   482:                                pushcp;
1.3       millert   483:                            else if (user_matches == TRUE && keepall)
                    484:                                pushcp;
1.10      millert   485:                            cmnd_matches = UNSPEC;
1.1       millert   486:                        }
                    487:                ;
                    488:
                    489: opcmnd         :       cmnd {
1.10      millert   490:                            SETMATCH(cmnd_matches, $1);
1.1       millert   491:                        }
                    492:                |       '!' {
                    493:                            if (printmatches == TRUE) {
                    494:                                if (in_alias == TRUE)
                    495:                                    append_entries("!", ", ");
                    496:                                else if (host_matches == TRUE &&
                    497:                                    user_matches == TRUE)
                    498:                                    append_cmnd("!", NULL);
                    499:                            }
                    500:                        } cmnd {
1.10      millert   501:                            SETNMATCH(cmnd_matches, $3);
1.1       millert   502:                        }
                    503:                ;
                    504:
                    505: runasspec      :       /* empty */ {
                    506:                            if (printmatches == TRUE && host_matches == TRUE &&
                    507:                                user_matches == TRUE) {
1.10      millert   508:                                if (runas_matches == UNSPEC) {
1.1       millert   509:                                    cm_list[cm_list_len].runas_len = 0;
                    510:                                } else {
                    511:                                    /* Inherit runas data. */
                    512:                                    cm_list[cm_list_len].runas =
                    513:                                        estrdup(cm_list[cm_list_len-1].runas);
                    514:                                    cm_list[cm_list_len].runas_len =
                    515:                                        cm_list[cm_list_len-1].runas_len;
                    516:                                    cm_list[cm_list_len].runas_size =
                    517:                                        cm_list[cm_list_len-1].runas_size;
                    518:                                }
                    519:                            }
                    520:                            /*
                    521:                             * If this is the first entry in a command list
                    522:                             * then check against default runas user.
                    523:                             */
1.10      millert   524:                            if (runas_matches == UNSPEC) {
1.18      millert   525:                                runas_matches = userpw_matches(def_runas_default,
                    526:                                    *user_runas, runas_pw) ? TRUE : NOMATCH;
1.10      millert   527:                            }
1.1       millert   528:                        }
1.2       millert   529:                |       RUNAS runaslist {
1.10      millert   530:                            runas_matches = $2;
1.2       millert   531:                        }
1.1       millert   532:                ;
                    533:
1.2       millert   534: runaslist      :       oprunasuser { ; }
                    535:                |       runaslist ',' oprunasuser {
                    536:                            /* Later entries override earlier ones. */
1.10      millert   537:                            if ($3 != NOMATCH)
1.2       millert   538:                                $$ = $3;
                    539:                            else
                    540:                                $$ = $1;
                    541:                        }
1.1       millert   542:                ;
                    543:
1.2       millert   544: oprunasuser    :       runasuser { ; }
1.1       millert   545:                |       '!' {
                    546:                            if (printmatches == TRUE) {
                    547:                                if (in_alias == TRUE)
                    548:                                    append_entries("!", ", ");
                    549:                                else if (host_matches == TRUE &&
                    550:                                    user_matches == TRUE)
                    551:                                    append_runas("!", ", ");
                    552:                            }
                    553:                        } runasuser {
1.2       millert   554:                            /* Set $$ to the negation of runasuser */
1.10      millert   555:                            $$ = ($3 == NOMATCH ? NOMATCH : ! $3);
1.1       millert   556:                        }
1.8       millert   557:                ;
1.1       millert   558:
                    559: runasuser      :       WORD {
                    560:                            if (printmatches == TRUE) {
                    561:                                if (in_alias == TRUE)
                    562:                                    append_entries($1, ", ");
                    563:                                else if (host_matches == TRUE &&
                    564:                                    user_matches == TRUE)
                    565:                                    append_runas($1, ", ");
                    566:                            }
1.10      millert   567:                            if (userpw_matches($1, *user_runas, runas_pw))
1.1       millert   568:                                $$ = TRUE;
                    569:                            else
1.10      millert   570:                                $$ = NOMATCH;
1.12      millert   571:                            efree($1);
1.10      millert   572:                            used_runas = TRUE;
1.1       millert   573:                        }
                    574:                |       USERGROUP {
                    575:                            if (printmatches == TRUE) {
                    576:                                if (in_alias == TRUE)
                    577:                                    append_entries($1, ", ");
                    578:                                else if (host_matches == TRUE &&
                    579:                                    user_matches == TRUE)
                    580:                                    append_runas($1, ", ");
                    581:                            }
1.10      millert   582:                            if (usergr_matches($1, *user_runas, runas_pw))
1.1       millert   583:                                $$ = TRUE;
                    584:                            else
1.10      millert   585:                                $$ = NOMATCH;
1.12      millert   586:                            efree($1);
1.10      millert   587:                            used_runas = TRUE;
1.1       millert   588:                        }
                    589:                |       NETGROUP {
                    590:                            if (printmatches == TRUE) {
                    591:                                if (in_alias == TRUE)
                    592:                                    append_entries($1, ", ");
                    593:                                else if (host_matches == TRUE &&
                    594:                                    user_matches == TRUE)
                    595:                                    append_runas($1, ", ");
                    596:                            }
1.3       millert   597:                            if (netgr_matches($1, NULL, NULL, *user_runas))
1.1       millert   598:                                $$ = TRUE;
                    599:                            else
1.10      millert   600:                                $$ = NOMATCH;
1.12      millert   601:                            efree($1);
1.10      millert   602:                            used_runas = TRUE;
1.1       millert   603:                        }
                    604:                |       ALIAS {
                    605:                            aliasinfo *aip = find_alias($1, RUNAS_ALIAS);
                    606:
                    607:                            if (printmatches == TRUE) {
                    608:                                if (in_alias == TRUE)
                    609:                                    append_entries($1, ", ");
                    610:                                else if (host_matches == TRUE &&
                    611:                                    user_matches == TRUE)
                    612:                                    append_runas($1, ", ");
                    613:                            }
                    614:                            /* could be an all-caps username */
                    615:                            if (aip)
                    616:                                $$ = aip->val;
                    617:                            else if (strcmp($1, *user_runas) == 0)
                    618:                                $$ = TRUE;
                    619:                            else {
                    620:                                if (pedantic) {
                    621:                                    (void) fprintf(stderr,
                    622:                                        "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
                    623:                                        (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
                    624:                                    if (pedantic > 1) {
                    625:                                        yyerror(NULL);
                    626:                                        YYERROR;
                    627:                                    }
                    628:                                }
1.10      millert   629:                                $$ = NOMATCH;
1.1       millert   630:                            }
1.12      millert   631:                            efree($1);
1.10      millert   632:                            used_runas = TRUE;
1.1       millert   633:                        }
                    634:                |       ALL {
                    635:                            if (printmatches == TRUE) {
                    636:                                if (in_alias == TRUE)
                    637:                                    append_entries("ALL", ", ");
                    638:                                else if (host_matches == TRUE &&
                    639:                                    user_matches == TRUE)
                    640:                                    append_runas("ALL", ", ");
                    641:                            }
                    642:                            $$ = TRUE;
                    643:                        }
                    644:                ;
                    645:
1.10      millert   646: cmndtag                :       /* empty */ {
1.12      millert   647:                            /* Inherit {NO,}{PASSWD,EXEC,SETENV} status. */
1.1       millert   648:                            if (printmatches == TRUE && host_matches == TRUE &&
                    649:                                user_matches == TRUE) {
                    650:                                if (no_passwd == TRUE)
                    651:                                    cm_list[cm_list_len].nopasswd = TRUE;
                    652:                                else
                    653:                                    cm_list[cm_list_len].nopasswd = FALSE;
1.10      millert   654:                                if (no_execve == TRUE)
                    655:                                    cm_list[cm_list_len].noexecve = TRUE;
                    656:                                else
                    657:                                    cm_list[cm_list_len].noexecve = FALSE;
1.12      millert   658:                                if (setenv_ok == TRUE)
                    659:                                    cm_list[cm_list_len].setenv = TRUE;
                    660:                                else
                    661:                                    cm_list[cm_list_len].setenv = FALSE;
1.1       millert   662:                            }
                    663:                        }
1.10      millert   664:                |       cmndtag NOPASSWD {
1.1       millert   665:                            no_passwd = TRUE;
                    666:                            if (printmatches == TRUE && host_matches == TRUE &&
                    667:                                user_matches == TRUE)
                    668:                                cm_list[cm_list_len].nopasswd = TRUE;
                    669:                        }
1.10      millert   670:                |       cmndtag PASSWD {
1.1       millert   671:                            no_passwd = FALSE;
                    672:                            if (printmatches == TRUE && host_matches == TRUE &&
                    673:                                user_matches == TRUE)
                    674:                                cm_list[cm_list_len].nopasswd = FALSE;
                    675:                        }
1.10      millert   676:                |       cmndtag NOEXEC {
                    677:                            no_execve = TRUE;
                    678:                            if (printmatches == TRUE && host_matches == TRUE &&
                    679:                                user_matches == TRUE)
                    680:                                cm_list[cm_list_len].noexecve = TRUE;
                    681:                        }
                    682:                |       cmndtag EXEC {
                    683:                            no_execve = FALSE;
                    684:                            if (printmatches == TRUE && host_matches == TRUE &&
                    685:                                user_matches == TRUE)
                    686:                                cm_list[cm_list_len].noexecve = FALSE;
                    687:                        }
1.12      millert   688:                |       cmndtag SETENV {
                    689:                            setenv_ok = TRUE;
                    690:                            if (printmatches == TRUE && host_matches == TRUE &&
                    691:                                user_matches == TRUE)
                    692:                                cm_list[cm_list_len].setenv = TRUE;
                    693:                        }
                    694:                |       cmndtag NOSETENV {
                    695:                            setenv_ok = FALSE;
                    696:                            if (printmatches == TRUE && host_matches == TRUE &&
                    697:                                user_matches == TRUE)
                    698:                                cm_list[cm_list_len].setenv = FALSE;
                    699:                        }
1.1       millert   700:                ;
                    701:
                    702: cmnd           :       ALL {
                    703:                            if (printmatches == TRUE) {
                    704:                                if (in_alias == TRUE)
                    705:                                    append_entries("ALL", ", ");
                    706:                                else if (host_matches == TRUE &&
                    707:                                    user_matches == TRUE) {
                    708:                                    append_cmnd("ALL", NULL);
                    709:                                    expand_match_list();
                    710:                                }
                    711:                            }
1.19      millert   712:                            /* sudo "ALL" implies the SETENV tag */
                    713:                            if (setenv_ok == UNSPEC)
                    714:                                setenv_ok = IMPLIED;
1.1       millert   715:
1.12      millert   716:                            efree(safe_cmnd);
                    717:                            safe_cmnd = NULL;
1.1       millert   718:                            $$ = TRUE;
                    719:                        }
                    720:                |       ALIAS {
                    721:                            aliasinfo *aip;
                    722:
                    723:                            if (printmatches == TRUE) {
                    724:                                if (in_alias == TRUE)
                    725:                                    append_entries($1, ", ");
                    726:                                else if (host_matches == TRUE &&
                    727:                                    user_matches == TRUE) {
                    728:                                    append_cmnd($1, NULL);
                    729:                                    expand_match_list();
                    730:                                }
                    731:                            }
                    732:
                    733:                            if ((aip = find_alias($1, CMND_ALIAS)))
                    734:                                $$ = aip->val;
                    735:                            else {
                    736:                                if (pedantic) {
                    737:                                    (void) fprintf(stderr,
                    738:                                        "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
                    739:                                        (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
                    740:                                    if (pedantic > 1) {
                    741:                                        yyerror(NULL);
                    742:                                        YYERROR;
                    743:                                    }
                    744:                                }
1.10      millert   745:                                $$ = NOMATCH;
1.1       millert   746:                            }
1.12      millert   747:                            efree($1);
1.1       millert   748:                        }
                    749:                |        COMMAND {
                    750:                            if (printmatches == TRUE) {
                    751:                                if (in_alias == TRUE) {
                    752:                                    append_entries($1.cmnd, ", ");
                    753:                                    if ($1.args)
                    754:                                        append_entries($1.args, " ");
                    755:                                }
                    756:                                if (host_matches == TRUE &&
                    757:                                    user_matches == TRUE)  {
                    758:                                    append_cmnd($1.cmnd, NULL);
                    759:                                    if ($1.args)
                    760:                                        append_cmnd($1.args, " ");
                    761:                                    expand_match_list();
                    762:                                }
                    763:                            }
                    764:
1.10      millert   765:                            if (command_matches($1.cmnd, $1.args))
1.1       millert   766:                                $$ = TRUE;
                    767:                            else
1.10      millert   768:                                $$ = NOMATCH;
1.1       millert   769:
1.12      millert   770:                            efree($1.cmnd);
                    771:                            efree($1.args);
1.1       millert   772:                        }
                    773:                ;
                    774:
                    775: hostaliases    :       hostalias
                    776:                |       hostaliases ':' hostalias
                    777:                ;
                    778:
                    779: hostalias      :       ALIAS { push; } '=' hostlist {
1.10      millert   780:                            if ((MATCHED(host_matches) || pedantic) &&
1.8       millert   781:                                !add_alias($1, HOST_ALIAS, host_matches)) {
                    782:                                yyerror(NULL);
1.1       millert   783:                                YYERROR;
1.8       millert   784:                            }
1.1       millert   785:                            pop;
                    786:                        }
                    787:                ;
                    788:
                    789: hostlist       :       ophost
                    790:                |       hostlist ',' ophost
                    791:                ;
                    792:
                    793: cmndaliases    :       cmndalias
                    794:                |       cmndaliases ':' cmndalias
                    795:                ;
                    796:
                    797: cmndalias      :       ALIAS {
                    798:                            push;
                    799:                            if (printmatches == TRUE) {
                    800:                                in_alias = TRUE;
                    801:                                /* Allocate space for ga_list if necessary. */
                    802:                                expand_ga_list();
                    803:                                ga_list[ga_list_len-1].type = CMND_ALIAS;
                    804:                                ga_list[ga_list_len-1].alias = estrdup($1);
                    805:                             }
                    806:                        } '=' cmndlist {
1.10      millert   807:                            if ((MATCHED(cmnd_matches) || pedantic) &&
1.8       millert   808:                                !add_alias($1, CMND_ALIAS, cmnd_matches)) {
                    809:                                yyerror(NULL);
1.1       millert   810:                                YYERROR;
1.8       millert   811:                            }
1.1       millert   812:                            pop;
1.12      millert   813:                            efree($1);
1.1       millert   814:
                    815:                            if (printmatches == TRUE)
                    816:                                in_alias = FALSE;
                    817:                        }
                    818:                ;
                    819:
                    820: cmndlist       :       opcmnd { ; }
                    821:                |       cmndlist ',' opcmnd
                    822:                ;
                    823:
                    824: runasaliases   :       runasalias
                    825:                |       runasaliases ':' runasalias
                    826:                ;
                    827:
                    828: runasalias     :       ALIAS {
                    829:                            if (printmatches == TRUE) {
                    830:                                in_alias = TRUE;
                    831:                                /* Allocate space for ga_list if necessary. */
                    832:                                expand_ga_list();
                    833:                                ga_list[ga_list_len-1].type = RUNAS_ALIAS;
                    834:                                ga_list[ga_list_len-1].alias = estrdup($1);
                    835:                            }
                    836:                        } '=' runaslist {
1.10      millert   837:                            if (($4 != NOMATCH || pedantic) &&
1.8       millert   838:                                !add_alias($1, RUNAS_ALIAS, $4)) {
                    839:                                yyerror(NULL);
1.1       millert   840:                                YYERROR;
1.8       millert   841:                            }
1.12      millert   842:                            efree($1);
1.1       millert   843:
                    844:                            if (printmatches == TRUE)
                    845:                                in_alias = FALSE;
                    846:                        }
                    847:                ;
                    848:
                    849: useraliases    :       useralias
                    850:                |       useraliases ':' useralias
                    851:                ;
                    852:
                    853: useralias      :       ALIAS { push; } '=' userlist {
1.10      millert   854:                            if ((MATCHED(user_matches) || pedantic) &&
1.8       millert   855:                                !add_alias($1, USER_ALIAS, user_matches)) {
                    856:                                yyerror(NULL);
1.1       millert   857:                                YYERROR;
1.8       millert   858:                            }
1.1       millert   859:                            pop;
1.12      millert   860:                            efree($1);
1.1       millert   861:                        }
                    862:                ;
                    863:
                    864: userlist       :       opuser
                    865:                |       userlist ',' opuser
                    866:                ;
                    867:
                    868: opuser         :       user {
1.10      millert   869:                            SETMATCH(user_matches, $1);
1.1       millert   870:                        }
                    871:                |       '!' user {
1.10      millert   872:                            SETNMATCH(user_matches, $2);
1.1       millert   873:                        }
1.8       millert   874:                ;
1.1       millert   875:
                    876: user           :       WORD {
1.10      millert   877:                            if (userpw_matches($1, user_name, sudo_user.pw))
1.1       millert   878:                                $$ = TRUE;
                    879:                            else
1.10      millert   880:                                $$ = NOMATCH;
1.12      millert   881:                            efree($1);
1.1       millert   882:                        }
                    883:                |       USERGROUP {
1.10      millert   884:                            if (usergr_matches($1, user_name, sudo_user.pw))
1.1       millert   885:                                $$ = TRUE;
                    886:                            else
1.10      millert   887:                                $$ = NOMATCH;
1.12      millert   888:                            efree($1);
1.1       millert   889:                        }
                    890:                |       NETGROUP {
1.3       millert   891:                            if (netgr_matches($1, NULL, NULL, user_name))
1.1       millert   892:                                $$ = TRUE;
                    893:                            else
1.10      millert   894:                                $$ = NOMATCH;
1.12      millert   895:                            efree($1);
1.1       millert   896:                        }
                    897:                |       ALIAS {
                    898:                            aliasinfo *aip = find_alias($1, USER_ALIAS);
                    899:
                    900:                            /* could be an all-caps username */
                    901:                            if (aip)
                    902:                                $$ = aip->val;
                    903:                            else if (strcmp($1, user_name) == 0)
                    904:                                $$ = TRUE;
                    905:                            else {
                    906:                                if (pedantic) {
                    907:                                    (void) fprintf(stderr,
                    908:                                        "%s: undeclared User_Alias `%s' referenced near line %d\n",
                    909:                                        (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
1.8       millert   910:                                    if (pedantic > 1) {
                    911:                                        yyerror(NULL);
1.1       millert   912:                                        YYERROR;
1.8       millert   913:                                    }
1.1       millert   914:                                }
1.10      millert   915:                                $$ = NOMATCH;
1.1       millert   916:                            }
1.12      millert   917:                            efree($1);
1.1       millert   918:                        }
                    919:                |       ALL {
                    920:                            $$ = TRUE;
                    921:                        }
                    922:                ;
                    923:
                    924: %%
                    925:
                    926: #define MOREALIASES (32)
                    927: aliasinfo *aliases = NULL;
                    928: size_t naliases = 0;
                    929: size_t nslots = 0;
                    930:
                    931:
                    932: /*
                    933:  * Compare two aliasinfo structures, strcmp() style.
                    934:  * Note that we do *not* compare their values.
                    935:  */
                    936: static int
                    937: aliascmp(a1, a2)
                    938:     const VOID *a1, *a2;
                    939: {
                    940:     int r;
                    941:     aliasinfo *ai1, *ai2;
                    942:
                    943:     ai1 = (aliasinfo *) a1;
                    944:     ai2 = (aliasinfo *) a2;
                    945:     if ((r = strcmp(ai1->name, ai2->name)) == 0)
                    946:        r = ai1->type - ai2->type;
                    947:
                    948:     return(r);
                    949: }
                    950:
                    951: /*
                    952:  * Compare two generic_alias structures, strcmp() style.
                    953:  */
                    954: static int
                    955: genaliascmp(entry, key)
                    956:     const VOID *entry, *key;
                    957: {
                    958:     int r;
                    959:     struct generic_alias *ga1, *ga2;
                    960:
                    961:     ga1 = (struct generic_alias *) key;
                    962:     ga2 = (struct generic_alias *) entry;
                    963:     if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
                    964:        r = ga1->type - ga2->type;
                    965:
                    966:     return(r);
                    967: }
                    968:
                    969:
                    970: /*
                    971:  * Adds the named alias of the specified type to the aliases list.
                    972:  */
                    973: static int
                    974: add_alias(alias, type, val)
                    975:     char *alias;
                    976:     int type;
                    977:     int val;
                    978: {
                    979:     aliasinfo ai, *aip;
                    980:     size_t onaliases;
                    981:     char s[512];
                    982:
1.16      millert   983:     if (naliases >= nslots)
                    984:        more_aliases();
1.1       millert   985:
                    986:     ai.type = type;
                    987:     ai.val = val;
                    988:     ai.name = estrdup(alias);
                    989:     onaliases = naliases;
                    990:
                    991:     aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
                    992:                                sizeof(ai), aliascmp);
                    993:     if (aip == NULL) {
                    994:        (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
                    995:                        alias);
                    996:        yyerror(s);
                    997:        return(FALSE);
                    998:     }
                    999:     if (onaliases == naliases) {
                   1000:        (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
                   1001:        yyerror(s);
                   1002:        return(FALSE);
                   1003:     }
                   1004:
                   1005:     return(TRUE);
                   1006: }
                   1007:
                   1008: /*
                   1009:  * Searches for the named alias of the specified type.
                   1010:  */
                   1011: static aliasinfo *
                   1012: find_alias(alias, type)
                   1013:     char *alias;
                   1014:     int type;
                   1015: {
                   1016:     aliasinfo ai;
                   1017:
                   1018:     ai.name = alias;
                   1019:     ai.type = type;
                   1020:
                   1021:     return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
                   1022:                 sizeof(ai), aliascmp));
                   1023: }
                   1024:
                   1025: /*
                   1026:  * Allocates more space for the aliases list.
                   1027:  */
1.16      millert  1028: static void
1.1       millert  1029: more_aliases()
                   1030: {
                   1031:
                   1032:     nslots += MOREALIASES;
1.16      millert  1033:     aliases = (aliasinfo *) erealloc3(aliases, nslots, sizeof(aliasinfo));
1.1       millert  1034: }
                   1035:
                   1036: /*
                   1037:  * Lists the contents of the aliases list.
                   1038:  */
                   1039: void
                   1040: dumpaliases()
                   1041: {
                   1042:     size_t n;
                   1043:
                   1044:     for (n = 0; n < naliases; n++) {
                   1045:        if (aliases[n].val == -1)
                   1046:            continue;
                   1047:
                   1048:        switch (aliases[n].type) {
                   1049:        case HOST_ALIAS:
                   1050:            (void) puts("HOST_ALIAS");
                   1051:            break;
                   1052:
                   1053:        case CMND_ALIAS:
                   1054:            (void) puts("CMND_ALIAS");
                   1055:            break;
                   1056:
                   1057:        case USER_ALIAS:
                   1058:            (void) puts("USER_ALIAS");
                   1059:            break;
                   1060:
                   1061:        case RUNAS_ALIAS:
                   1062:            (void) puts("RUNAS_ALIAS");
                   1063:            break;
                   1064:        }
                   1065:        (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
                   1066:     }
                   1067: }
                   1068:
                   1069: /*
                   1070:  * Lists the contents of cm_list and ga_list for `sudo -l'.
                   1071:  */
                   1072: void
                   1073: list_matches()
                   1074: {
1.10      millert  1075:     size_t count;
1.1       millert  1076:     char *p;
                   1077:     struct generic_alias *ga, key;
                   1078:
                   1079:     (void) printf("User %s may run the following commands on this host:\n",
                   1080:        user_name);
1.8       millert  1081:     for (count = 0; count < cm_list_len; count++) {
1.1       millert  1082:
                   1083:        /* Print the runas list. */
                   1084:        (void) fputs("    ", stdout);
1.8       millert  1085:        if (cm_list[count].runas) {
1.1       millert  1086:            (void) putchar('(');
1.8       millert  1087:            p = strtok(cm_list[count].runas, ", ");
1.1       millert  1088:            do {
1.8       millert  1089:                if (p != cm_list[count].runas)
1.1       millert  1090:                    (void) fputs(", ", stdout);
                   1091:
                   1092:                key.alias = p;
                   1093:                key.type = RUNAS_ALIAS;
                   1094:                if ((ga = (struct generic_alias *) lfind((VOID *) &key,
                   1095:                    (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
                   1096:                    (void) fputs(ga->entries, stdout);
                   1097:                else
                   1098:                    (void) fputs(p, stdout);
                   1099:            } while ((p = strtok(NULL, ", ")));
                   1100:            (void) fputs(") ", stdout);
                   1101:        } else {
1.10      millert  1102:            (void) printf("(%s) ", def_runas_default);
1.1       millert  1103:        }
                   1104:
1.10      millert  1105:        /* Is execve(2) disabled? */
                   1106:        if (cm_list[count].noexecve == TRUE && !def_noexec)
                   1107:            (void) fputs("NOEXEC: ", stdout);
                   1108:        else if (cm_list[count].noexecve == FALSE && def_noexec)
                   1109:            (void) fputs("EXEC: ", stdout);
                   1110:
1.1       millert  1111:        /* Is a password required? */
1.10      millert  1112:        if (cm_list[count].nopasswd == TRUE && def_authenticate)
1.1       millert  1113:            (void) fputs("NOPASSWD: ", stdout);
1.10      millert  1114:        else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
1.1       millert  1115:            (void) fputs("PASSWD: ", stdout);
                   1116:
1.12      millert  1117:        /* Is setenv enabled? */
                   1118:        if (cm_list[count].setenv == TRUE && !def_setenv)
                   1119:            (void) fputs("SETENV: ", stdout);
                   1120:        else if (cm_list[count].setenv == FALSE && def_setenv)
                   1121:            (void) fputs("NOSETENV: ", stdout);
                   1122:
1.1       millert  1123:        /* Print the actual command or expanded Cmnd_Alias. */
1.8       millert  1124:        key.alias = cm_list[count].cmnd;
1.1       millert  1125:        key.type = CMND_ALIAS;
                   1126:        if ((ga = (struct generic_alias *) lfind((VOID *) &key,
                   1127:            (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
                   1128:            (void) puts(ga->entries);
                   1129:        else
1.8       millert  1130:            (void) puts(cm_list[count].cmnd);
1.1       millert  1131:     }
                   1132:
                   1133:     /* Be nice and free up space now that we are done. */
1.8       millert  1134:     for (count = 0; count < ga_list_len; count++) {
1.12      millert  1135:        efree(ga_list[count].alias);
                   1136:        efree(ga_list[count].entries);
1.1       millert  1137:     }
1.12      millert  1138:     efree(ga_list);
1.1       millert  1139:     ga_list = NULL;
                   1140:
1.8       millert  1141:     for (count = 0; count < cm_list_len; count++) {
1.12      millert  1142:        efree(cm_list[count].runas);
                   1143:        efree(cm_list[count].cmnd);
1.1       millert  1144:     }
1.12      millert  1145:     efree(cm_list);
1.1       millert  1146:     cm_list = NULL;
                   1147:     cm_list_len = 0;
                   1148:     cm_list_size = 0;
                   1149: }
                   1150:
                   1151: /*
                   1152:  * Appends a source string to the destination, optionally prefixing a separator.
                   1153:  */
                   1154: static void
                   1155: append(src, dstp, dst_len, dst_size, separator)
                   1156:     char *src, **dstp;
                   1157:     size_t *dst_len, *dst_size;
                   1158:     char *separator;
                   1159: {
                   1160:     size_t src_len = strlen(src);
                   1161:     char *dst = *dstp;
                   1162:
                   1163:     /*
                   1164:      * Only add the separator if there is something to separate from.
                   1165:      * If the last char is a '!', don't apply the separator (XXX).
                   1166:      */
                   1167:     if (separator && dst && dst[*dst_len - 1] != '!')
                   1168:        src_len += strlen(separator);
                   1169:     else
                   1170:        separator = NULL;
                   1171:
                   1172:     /* Assumes dst will be NULL if not set. */
                   1173:     if (dst == NULL) {
                   1174:        dst = (char *) emalloc(BUFSIZ);
1.8       millert  1175:        *dst = '\0';
1.1       millert  1176:        *dst_size = BUFSIZ;
                   1177:        *dst_len = 0;
                   1178:        *dstp = dst;
                   1179:     }
                   1180:
                   1181:     /* Allocate more space if necessary. */
                   1182:     if (*dst_size <= *dst_len + src_len) {
                   1183:        while (*dst_size <= *dst_len + src_len)
                   1184:            *dst_size += BUFSIZ;
                   1185:
                   1186:        dst = (char *) erealloc(dst, *dst_size);
                   1187:        *dstp = dst;
                   1188:     }
                   1189:
                   1190:     /* Copy src -> dst adding a separator if appropriate and adjust len. */
1.8       millert  1191:     if (separator)
                   1192:        (void) strlcat(dst, separator, *dst_size);
                   1193:     (void) strlcat(dst, src, *dst_size);
1.1       millert  1194:     *dst_len += src_len;
                   1195: }
                   1196:
                   1197: /*
                   1198:  * Frees up space used by the aliases list and resets the associated counters.
                   1199:  */
                   1200: void
                   1201: reset_aliases()
                   1202: {
                   1203:     size_t n;
                   1204:
                   1205:     if (aliases) {
                   1206:        for (n = 0; n < naliases; n++)
1.12      millert  1207:            efree(aliases[n].name);
                   1208:        efree(aliases);
1.1       millert  1209:        aliases = NULL;
                   1210:     }
                   1211:     naliases = nslots = 0;
                   1212: }
                   1213:
                   1214: /*
                   1215:  * Increments ga_list_len, allocating more space as necessary.
                   1216:  */
                   1217: static void
                   1218: expand_ga_list()
                   1219: {
                   1220:
                   1221:     if (++ga_list_len >= ga_list_size) {
                   1222:        while ((ga_list_size += STACKINCREMENT) < ga_list_len)
                   1223:            ;
                   1224:        ga_list = (struct generic_alias *)
1.8       millert  1225:            erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
1.1       millert  1226:     }
                   1227:
                   1228:     ga_list[ga_list_len - 1].entries = NULL;
                   1229: }
                   1230:
                   1231: /*
                   1232:  * Increments cm_list_len, allocating more space as necessary.
                   1233:  */
                   1234: static void
                   1235: expand_match_list()
                   1236: {
                   1237:
                   1238:     if (++cm_list_len >= cm_list_size) {
                   1239:        while ((cm_list_size += STACKINCREMENT) < cm_list_len)
                   1240:            ;
                   1241:        if (cm_list == NULL)
                   1242:            cm_list_len = 0;            /* start at 0 since it is a subscript */
                   1243:        cm_list = (struct command_match *)
1.8       millert  1244:            erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
1.1       millert  1245:     }
                   1246:
                   1247:     cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
                   1248:     cm_list[cm_list_len].nopasswd = FALSE;
1.10      millert  1249:     cm_list[cm_list_len].noexecve = FALSE;
1.12      millert  1250:     cm_list[cm_list_len].setenv = FALSE;
1.1       millert  1251: }
                   1252:
                   1253: /*
                   1254:  * Frees up spaced used by a previous parser run and allocates new space
                   1255:  * for various data structures.
                   1256:  */
                   1257: void
                   1258: init_parser()
                   1259: {
                   1260:
                   1261:     /* Free up old data structures if we run the parser more than once. */
                   1262:     if (match) {
1.12      millert  1263:        efree(match);
1.1       millert  1264:        match = NULL;
                   1265:        top = 0;
                   1266:        parse_error = FALSE;
1.10      millert  1267:        used_runas = FALSE;
                   1268:        errorlineno = -1;
                   1269:        sudolineno = 1;
1.1       millert  1270:     }
                   1271:
                   1272:     /* Allocate space for the matching stack. */
                   1273:     stacksize = STACKINCREMENT;
1.8       millert  1274:     match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
1.1       millert  1275:
                   1276:     /* Allocate space for the match list (for `sudo -l'). */
                   1277:     if (printmatches == TRUE)
                   1278:        expand_match_list();
                   1279: }