[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.1

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