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

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