Annotation of embedaddon/sudo/plugins/sudoers/toke.l, revision 1.1.1.5

1.1       misho       1: %{
                      2: /*
1.1.1.4   misho       3:  * Copyright (c) 1996, 1998-2005, 2007-2013
1.1       misho       4:  *     Todd C. Miller <Todd.Miller@courtesan.com>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     18:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     19:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     20:  *
                     21:  * Sponsored in part by the Defense Advanced Research Projects
                     22:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
                     23:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
                     24:  */
                     25: 
                     26: #include <config.h>
                     27: 
                     28: #include <sys/types.h>
                     29: #include <sys/stat.h>
                     30: #include <stdio.h>
                     31: #ifdef STDC_HEADERS
                     32: # include <stdlib.h>
                     33: # include <stddef.h>
                     34: #else
                     35: # ifdef HAVE_STDLIB_H
                     36: #  include <stdlib.h>
                     37: # endif
                     38: #endif /* STDC_HEADERS */
                     39: #ifdef HAVE_STRING_H
                     40: # include <string.h>
                     41: #endif /* HAVE_STRING_H */
                     42: #ifdef HAVE_STRINGS_H
                     43: # include <strings.h>
                     44: #endif /* HAVE_STRINGS_H */
1.1.1.4   misho      45: #if defined(HAVE_STDINT_H)
                     46: # include <stdint.h>
                     47: #elif defined(HAVE_INTTYPES_H)
                     48: # include <inttypes.h>
                     49: #endif
1.1       misho      50: #ifdef HAVE_UNISTD_H
                     51: # include <unistd.h>
                     52: #endif /* HAVE_UNISTD_H */
                     53: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
                     54: # include <malloc.h>
                     55: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
                     56: #ifdef HAVE_DIRENT_H
                     57: # include <dirent.h>
                     58: # define NAMLEN(dirent) strlen((dirent)->d_name)
                     59: #else
                     60: # define dirent direct
                     61: # define NAMLEN(dirent) (dirent)->d_namlen
                     62: # ifdef HAVE_SYS_NDIR_H
                     63: #  include <sys/ndir.h>
                     64: # endif
                     65: # ifdef HAVE_SYS_DIR_H
                     66: #  include <sys/dir.h>
                     67: # endif
                     68: # ifdef HAVE_NDIR_H
                     69: #  include <ndir.h>
                     70: # endif
                     71: #endif
                     72: #include <errno.h>
                     73: #include <ctype.h>
                     74: #include "sudoers.h"
                     75: #include "parse.h"
                     76: #include "toke.h"
                     77: #include <gram.h>
1.1.1.2   misho      78: #include "lbuf.h"
1.1.1.4   misho      79: #include "sha2.h"
1.1.1.2   misho      80: #include "secure_path.h"
1.1       misho      81: 
1.1.1.5 ! misho      82: int sudolineno;                        /* current sudoers line number. */
        !            83: int last_token;                        /* last token that was parsed. */
        !            84: char *sudoers;                 /* sudoers file being parsed. */
1.1       misho      85: 
1.1.1.2   misho      86: /* Default sudoers path, mode and owner (may be set via sudo.conf) */
                     87: const char *sudoers_file = _PATH_SUDOERS;
                     88: mode_t sudoers_mode = SUDOERS_MODE;
                     89: uid_t sudoers_uid = SUDOERS_UID;
                     90: gid_t sudoers_gid = SUDOERS_GID;
1.1       misho      91: 
1.1.1.2   misho      92: static bool continued, sawspace;
                     93: static int prev_state;
1.1.1.4   misho      94: static int digest_len;
1.1.1.2   misho      95: 
                     96: static bool _push_include(char *, bool);
                     97: static bool pop_include(void);
1.1       misho      98: static char *parse_include(char *);
                     99: 
                    100: int (*trace_print)(const char *msg) = sudoers_trace_print;
                    101: 
1.1.1.2   misho     102: #define LEXRETURN(n)   do {    \
                    103:        last_token = (n);       \
                    104:        return (n);             \
                    105: } while (0)
                    106: 
1.1.1.4   misho     107: #define ECHO   ignore_result(fwrite(sudoerstext, sudoersleng, 1, sudoersout))
1.1.1.2   misho     108: 
                    109: #define        push_include(_p)        (_push_include((_p), false))
                    110: #define        push_includedir(_p)     (_push_include((_p), true))
1.1       misho     111: %}
                    112: 
                    113: HEX16                  [0-9A-Fa-f]{1,4}
                    114: OCTET                  (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
                    115: IPV4ADDR               {OCTET}(\.{OCTET}){3}
                    116: IPV6ADDR               ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
                    117: 
                    118: HOSTNAME               [[:alnum:]_-]+
                    119: WORD                   ([^#>!=:,\(\) \t\n\\\"]|\\[^\n])+
                    120: ID                     #-?[0-9]+
                    121: PATH                   \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+
                    122: ENVAR                  ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])*
                    123: DEFVAR                 [a-z_]+
                    124: 
                    125: %option noinput
                    126: %option nounput
                    127: %option noyywrap
1.1.1.4   misho     128: %option prefix="sudoers"
1.1       misho     129: 
                    130: %s     GOTDEFS
                    131: %x     GOTCMND
                    132: %x     STARTDEFS
                    133: %x     INDEFS
                    134: %x     INSTR
1.1.1.4   misho     135: %s     WANTDIGEST
1.1       misho     136: 
                    137: %%
                    138: <GOTDEFS>[[:blank:]]*,[[:blank:]]* {
                    139:                            LEXTRACE(", ");
1.1.1.2   misho     140:                            LEXRETURN(',');
1.1       misho     141:                        }                       /* return ',' */
                    142: 
                    143: <GOTDEFS>[[:blank:]]+  BEGIN STARTDEFS;
                    144: 
                    145: <STARTDEFS>{DEFVAR}    {
                    146:                            BEGIN INDEFS;
                    147:                            LEXTRACE("DEFVAR ");
1.1.1.4   misho     148:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     149:                                yyterminate();
1.1.1.2   misho     150:                            LEXRETURN(DEFVAR);
1.1       misho     151:                        }
                    152: 
                    153: <INDEFS>{
                    154:     ,                  {
                    155:                            BEGIN STARTDEFS;
                    156:                            LEXTRACE(", ");
1.1.1.2   misho     157:                            LEXRETURN(',');
1.1       misho     158:                        }                       /* return ',' */
                    159: 
                    160:     =                  {
                    161:                            LEXTRACE("= ");
1.1.1.2   misho     162:                            LEXRETURN('=');
1.1       misho     163:                        }                       /* return '=' */
                    164: 
                    165:     \+=                        {
                    166:                            LEXTRACE("+= ");
1.1.1.2   misho     167:                            LEXRETURN('+');
1.1       misho     168:                        }                       /* return '+' */
                    169: 
                    170:     -=                 {
                    171:                            LEXTRACE("-= ");
1.1.1.2   misho     172:                            LEXRETURN('-');
1.1       misho     173:                        }                       /* return '-' */
                    174: 
                    175:     \"                 {
                    176:                            LEXTRACE("BEGINSTR ");
1.1.1.4   misho     177:                            sudoerslval.string = NULL;
1.1       misho     178:                            prev_state = YY_START;
                    179:                            BEGIN INSTR;
                    180:                        }
                    181: 
                    182:     {ENVAR}            {
                    183:                            LEXTRACE("WORD(2) ");
1.1.1.4   misho     184:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     185:                                yyterminate();
1.1.1.2   misho     186:                            LEXRETURN(WORD);
1.1       misho     187:                        }
                    188: }
                    189: 
                    190: <INSTR>{
                    191:     \\[[:blank:]]*\n[[:blank:]]*       {
                    192:                            /* Line continuation char followed by newline. */
1.1.1.2   misho     193:                            sudolineno++;
                    194:                            continued = true;
1.1       misho     195:                        }
                    196: 
                    197:     \"                 {
                    198:                            LEXTRACE("ENDSTR ");
                    199:                            BEGIN prev_state;
                    200: 
1.1.1.4   misho     201:                            if (sudoerslval.string == NULL) {
1.1       misho     202:                                LEXTRACE("ERROR "); /* empty string */
1.1.1.2   misho     203:                                LEXRETURN(ERROR);
1.1       misho     204:                            }
                    205:                            if (prev_state == INITIAL) {
1.1.1.4   misho     206:                                switch (sudoerslval.string[0]) {
1.1       misho     207:                                case '%':
1.1.1.4   misho     208:                                    if (sudoerslval.string[1] == '\0' ||
                    209:                                        (sudoerslval.string[1] == ':' &&
                    210:                                        sudoerslval.string[2] == '\0')) {
1.1       misho     211:                                        LEXTRACE("ERROR "); /* empty group */
1.1.1.2   misho     212:                                        LEXRETURN(ERROR);
1.1       misho     213:                                    }
                    214:                                    LEXTRACE("USERGROUP ");
1.1.1.2   misho     215:                                    LEXRETURN(USERGROUP);
1.1       misho     216:                                case '+':
1.1.1.4   misho     217:                                    if (sudoerslval.string[1] == '\0') {
1.1       misho     218:                                        LEXTRACE("ERROR "); /* empty netgroup */
1.1.1.2   misho     219:                                        LEXRETURN(ERROR);
1.1       misho     220:                                    }
                    221:                                    LEXTRACE("NETGROUP ");
1.1.1.2   misho     222:                                    LEXRETURN(NETGROUP);
1.1       misho     223:                                }
                    224:                            }
                    225:                            LEXTRACE("WORD(4) ");
1.1.1.2   misho     226:                            LEXRETURN(WORD);
1.1       misho     227:                        }
                    228: 
                    229:     \\                 {
                    230:                            LEXTRACE("BACKSLASH ");
1.1.1.4   misho     231:                            if (!append(sudoerstext, sudoersleng))
1.1       misho     232:                                yyterminate();
                    233:                        }
                    234: 
                    235:     ([^\"\n\\]|\\\")+  {
                    236:                            LEXTRACE("STRBODY ");
1.1.1.4   misho     237:                            if (!append(sudoerstext, sudoersleng))
1.1       misho     238:                                yyterminate();
                    239:                        }
                    240: }
                    241: 
                    242: <GOTCMND>{
                    243:     \\[\*\?\[\]\!]     {
                    244:                            /* quoted fnmatch glob char, pass verbatim */
                    245:                            LEXTRACE("QUOTEDCHAR ");
1.1.1.4   misho     246:                            if (!fill_args(sudoerstext, 2, sawspace))
1.1       misho     247:                                yyterminate();
1.1.1.2   misho     248:                            sawspace = false;
1.1       misho     249:                        }
                    250: 
                    251:     \\[:\\,= \t#]      {
                    252:                            /* quoted sudoers special char, strip backslash */
                    253:                            LEXTRACE("QUOTEDCHAR ");
1.1.1.4   misho     254:                            if (!fill_args(sudoerstext + 1, 1, sawspace))
1.1       misho     255:                                yyterminate();
1.1.1.2   misho     256:                            sawspace = false;
1.1       misho     257:                        }
                    258: 
                    259:     [#:\,=\n]          {
                    260:                            BEGIN INITIAL;
                    261:                            yyless(0);
1.1.1.2   misho     262:                            LEXRETURN(COMMAND);
1.1       misho     263:                        }                       /* end of command line args */
                    264: 
                    265:     [^#\\:, \t\n]+     {
                    266:                            LEXTRACE("ARG ");
1.1.1.4   misho     267:                            if (!fill_args(sudoerstext, sudoersleng, sawspace))
1.1       misho     268:                                yyterminate();
1.1.1.2   misho     269:                            sawspace = false;
1.1       misho     270:                        }                       /* a command line arg */
                    271: }
                    272: 
1.1.1.4   misho     273: <WANTDIGEST>[[:xdigit:]]+ {
                    274:                            /* Only return DIGEST if the length is correct. */
                    275:                            if (sudoersleng == digest_len * 2) {
                    276:                                if (!fill(sudoerstext, sudoersleng))
                    277:                                    yyterminate();
                    278:                                BEGIN INITIAL;
                    279:                                LEXTRACE("DIGEST ");
                    280:                                LEXRETURN(DIGEST);
                    281:                            }
                    282:                            BEGIN INITIAL;
                    283:                            yyless(sudoersleng);
                    284:                        } /* hex digest */
                    285: 
                    286: <WANTDIGEST>[A-Za-z0-9\+/=]+ {
                    287:                            /* Only return DIGEST if the length is correct. */
1.1.1.5 ! misho     288:                            int len;
1.1.1.4   misho     289:                            if (sudoerstext[sudoersleng - 1] == '=') {
                    290:                                /* use padding */
                    291:                                len = 4 * ((digest_len + 2) / 3);
                    292:                            } else {
                    293:                                /* no padding */
                    294:                                len = (4 * digest_len + 2) / 3;
                    295:                            }
                    296:                            if (sudoersleng == len) {
                    297:                                if (!fill(sudoerstext, sudoersleng))
                    298:                                    yyterminate();
                    299:                                BEGIN INITIAL;
                    300:                                LEXTRACE("DIGEST ");
                    301:                                LEXRETURN(DIGEST);
                    302:                            }
                    303:                            BEGIN INITIAL;
                    304:                            yyless(sudoersleng);
                    305:                        } /* base64 digest */
                    306: 
1.1.1.2   misho     307: <INITIAL>^#include[[:blank:]]+.*\n {
1.1       misho     308:                            char *path;
                    309: 
                    310:                            if (continued) {
                    311:                                LEXTRACE("ERROR ");
1.1.1.2   misho     312:                                LEXRETURN(ERROR);
1.1       misho     313:                            }
                    314: 
1.1.1.4   misho     315:                            if ((path = parse_include(sudoerstext)) == NULL)
1.1       misho     316:                                yyterminate();
                    317: 
                    318:                            LEXTRACE("INCLUDE\n");
                    319: 
                    320:                            /* Push current buffer and switch to include file */
                    321:                            if (!push_include(path))
                    322:                                yyterminate();
                    323:                        }
                    324: 
1.1.1.2   misho     325: <INITIAL>^#includedir[[:blank:]]+.*\n {
1.1       misho     326:                            char *path;
                    327: 
                    328:                            if (continued) {
                    329:                                LEXTRACE("ERROR ");
1.1.1.2   misho     330:                                LEXRETURN(ERROR);
1.1       misho     331:                            }
                    332: 
1.1.1.4   misho     333:                            if ((path = parse_include(sudoerstext)) == NULL)
1.1       misho     334:                                yyterminate();
                    335: 
                    336:                            LEXTRACE("INCLUDEDIR\n");
                    337: 
                    338:                            /*
                    339:                             * Push current buffer and switch to include file.
                    340:                             * We simply ignore empty directories.
                    341:                             */
                    342:                            if (!push_includedir(path) && parse_error)
                    343:                                yyterminate();
                    344:                        }
                    345: 
                    346: <INITIAL>^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? {
                    347:                            char deftype;
                    348:                            int n;
                    349: 
                    350:                            if (continued) {
                    351:                                LEXTRACE("ERROR ");
1.1.1.2   misho     352:                                LEXRETURN(ERROR);
1.1       misho     353:                            }
                    354: 
1.1.1.4   misho     355:                            for (n = 0; isblank((unsigned char)sudoerstext[n]); n++)
1.1       misho     356:                                continue;
                    357:                            n += sizeof("Defaults") - 1;
1.1.1.4   misho     358:                            if ((deftype = sudoerstext[n++]) != '\0') {
                    359:                                while (isblank((unsigned char)sudoerstext[n]))
1.1       misho     360:                                    n++;
                    361:                            }
                    362:                            BEGIN GOTDEFS;
                    363:                            switch (deftype) {
                    364:                                case ':':
                    365:                                    yyless(n);
                    366:                                    LEXTRACE("DEFAULTS_USER ");
1.1.1.2   misho     367:                                    LEXRETURN(DEFAULTS_USER);
1.1       misho     368:                                case '>':
                    369:                                    yyless(n);
                    370:                                    LEXTRACE("DEFAULTS_RUNAS ");
1.1.1.2   misho     371:                                    LEXRETURN(DEFAULTS_RUNAS);
1.1       misho     372:                                case '@':
                    373:                                    yyless(n);
                    374:                                    LEXTRACE("DEFAULTS_HOST ");
1.1.1.2   misho     375:                                    LEXRETURN(DEFAULTS_HOST);
1.1       misho     376:                                case '!':
                    377:                                    yyless(n);
                    378:                                    LEXTRACE("DEFAULTS_CMND ");
1.1.1.2   misho     379:                                    LEXRETURN(DEFAULTS_CMND);
1.1       misho     380:                                default:
                    381:                                    LEXTRACE("DEFAULTS ");
1.1.1.2   misho     382:                                    LEXRETURN(DEFAULTS);
1.1       misho     383:                            }
                    384:                        }
                    385: 
                    386: <INITIAL>^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias     {
                    387:                            int n;
                    388: 
                    389:                            if (continued) {
                    390:                                LEXTRACE("ERROR ");
1.1.1.2   misho     391:                                LEXRETURN(ERROR);
1.1       misho     392:                            }
                    393: 
1.1.1.4   misho     394:                            for (n = 0; isblank((unsigned char)sudoerstext[n]); n++)
1.1       misho     395:                                continue;
1.1.1.4   misho     396:                            switch (sudoerstext[n]) {
1.1       misho     397:                                case 'H':
                    398:                                    LEXTRACE("HOSTALIAS ");
1.1.1.2   misho     399:                                    LEXRETURN(HOSTALIAS);
1.1       misho     400:                                case 'C':
                    401:                                    LEXTRACE("CMNDALIAS ");
1.1.1.2   misho     402:                                    LEXRETURN(CMNDALIAS);
1.1       misho     403:                                case 'U':
                    404:                                    LEXTRACE("USERALIAS ");
1.1.1.2   misho     405:                                    LEXRETURN(USERALIAS);
1.1       misho     406:                                case 'R':
                    407:                                    LEXTRACE("RUNASALIAS ");
1.1.1.2   misho     408:                                    LEXRETURN(RUNASALIAS);
1.1       misho     409:                            }
                    410:                        }
                    411: 
                    412: NOPASSWD[[:blank:]]*:  {
                    413:                                /* cmnd does not require passwd for this user */
                    414:                                LEXTRACE("NOPASSWD ");
1.1.1.2   misho     415:                                LEXRETURN(NOPASSWD);
1.1       misho     416:                        }
                    417: 
                    418: PASSWD[[:blank:]]*:    {
                    419:                                /* cmnd requires passwd for this user */
                    420:                                LEXTRACE("PASSWD ");
1.1.1.2   misho     421:                                LEXRETURN(PASSWD);
1.1       misho     422:                        }
                    423: 
                    424: NOEXEC[[:blank:]]*:    {
                    425:                                LEXTRACE("NOEXEC ");
1.1.1.2   misho     426:                                LEXRETURN(NOEXEC);
1.1       misho     427:                        }
                    428: 
                    429: EXEC[[:blank:]]*:      {
                    430:                                LEXTRACE("EXEC ");
1.1.1.2   misho     431:                                LEXRETURN(EXEC);
1.1       misho     432:                        }
                    433: 
                    434: SETENV[[:blank:]]*:    {
                    435:                                LEXTRACE("SETENV ");
1.1.1.2   misho     436:                                LEXRETURN(SETENV);
1.1       misho     437:                        }
                    438: 
                    439: NOSETENV[[:blank:]]*:  {
                    440:                                LEXTRACE("NOSETENV ");
1.1.1.2   misho     441:                                LEXRETURN(NOSETENV);
1.1       misho     442:                        }
                    443: 
                    444: LOG_OUTPUT[[:blank:]]*:        {
                    445:                                LEXTRACE("LOG_OUTPUT ");
1.1.1.2   misho     446:                                LEXRETURN(LOG_OUTPUT);
1.1       misho     447:                        }
                    448: 
                    449: NOLOG_OUTPUT[[:blank:]]*:      {
                    450:                                LEXTRACE("NOLOG_OUTPUT ");
1.1.1.2   misho     451:                                LEXRETURN(NOLOG_OUTPUT);
1.1       misho     452:                        }
                    453: 
                    454: LOG_INPUT[[:blank:]]*: {
                    455:                                LEXTRACE("LOG_INPUT ");
1.1.1.2   misho     456:                                LEXRETURN(LOG_INPUT);
1.1       misho     457:                        }
                    458: 
                    459: NOLOG_INPUT[[:blank:]]*:       {
                    460:                                LEXTRACE("NOLOG_INPUT ");
1.1.1.2   misho     461:                                LEXRETURN(NOLOG_INPUT);
1.1       misho     462:                        }
                    463: 
                    464: <INITIAL,GOTDEFS>(\+|\%|\%:) {
                    465:                            /* empty group or netgroup */
                    466:                            LEXTRACE("ERROR ");
1.1.1.2   misho     467:                            LEXRETURN(ERROR);
1.1       misho     468:                        }
                    469: 
                    470: \+{WORD}               {
                    471:                            /* netgroup */
1.1.1.4   misho     472:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     473:                                yyterminate();
                    474:                            LEXTRACE("NETGROUP ");
1.1.1.2   misho     475:                            LEXRETURN(NETGROUP);
1.1       misho     476:                        }
                    477: 
                    478: \%:?({WORD}|{ID})      {
                    479:                            /* group */
1.1.1.4   misho     480:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     481:                                yyterminate();
                    482:                            LEXTRACE("USERGROUP ");
1.1.1.2   misho     483:                            LEXRETURN(USERGROUP);
1.1       misho     484:                        }
                    485: 
                    486: {IPV4ADDR}(\/{IPV4ADDR})? {
1.1.1.4   misho     487:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     488:                                yyterminate();
                    489:                            LEXTRACE("NTWKADDR ");
1.1.1.2   misho     490:                            LEXRETURN(NTWKADDR);
1.1       misho     491:                        }
                    492: 
                    493: {IPV4ADDR}\/([12]?[0-9]|3[0-2]) {
1.1.1.4   misho     494:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     495:                                yyterminate();
                    496:                            LEXTRACE("NTWKADDR ");
1.1.1.2   misho     497:                            LEXRETURN(NTWKADDR);
1.1       misho     498:                        }
                    499: 
                    500: {IPV6ADDR}(\/{IPV6ADDR})? {
1.1.1.4   misho     501:                            if (!ipv6_valid(sudoerstext)) {
1.1       misho     502:                                LEXTRACE("ERROR ");
1.1.1.2   misho     503:                                LEXRETURN(ERROR);
1.1       misho     504:                            }
1.1.1.4   misho     505:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     506:                                yyterminate();
                    507:                            LEXTRACE("NTWKADDR ");
1.1.1.2   misho     508:                            LEXRETURN(NTWKADDR);
1.1       misho     509:                        }
                    510: 
                    511: {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
1.1.1.4   misho     512:                            if (!ipv6_valid(sudoerstext)) {
1.1       misho     513:                                LEXTRACE("ERROR ");
1.1.1.2   misho     514:                                LEXRETURN(ERROR);
1.1       misho     515:                            }
1.1.1.4   misho     516:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     517:                                yyterminate();
                    518:                            LEXTRACE("NTWKADDR ");
1.1.1.2   misho     519:                            LEXRETURN(NTWKADDR);
1.1       misho     520:                        }
                    521: 
                    522: ALL {
                    523:                            LEXTRACE("ALL ");
1.1.1.2   misho     524:                            LEXRETURN(ALL);
1.1       misho     525: 
                    526:                        }
                    527: 
                    528: <INITIAL>ROLE {
                    529: #ifdef HAVE_SELINUX
                    530:                            LEXTRACE("ROLE ");
1.1.1.2   misho     531:                            LEXRETURN(ROLE);
1.1       misho     532: #else
                    533:                            goto got_alias;
                    534: #endif
                    535:                        }
                    536: 
                    537: <INITIAL>TYPE {
                    538: #ifdef HAVE_SELINUX
                    539:                            LEXTRACE("TYPE ");
1.1.1.2   misho     540:                            LEXRETURN(TYPE);
1.1       misho     541: #else
                    542:                            goto got_alias;
                    543: #endif
                    544:                        }
1.1.1.3   misho     545: <INITIAL>PRIVS {
                    546: #ifdef HAVE_PRIV_SET
                    547:                            LEXTRACE("PRIVS ");
                    548:                            LEXRETURN(PRIVS);
                    549: #else
                    550:                            goto got_alias;
                    551: #endif
                    552:                        }
                    553: 
                    554: <INITIAL>LIMITPRIVS {
                    555: #ifdef HAVE_PRIV_SET
                    556:                            LEXTRACE("LIMITPRIVS ");
                    557:                            LEXRETURN(LIMITPRIVS);
                    558: #else
                    559:                            goto got_alias;
                    560: #endif
                    561:                        }
1.1       misho     562: 
                    563: [[:upper:]][[:upper:][:digit:]_]* {
                    564:                        got_alias:
1.1.1.4   misho     565:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     566:                                yyterminate();
                    567:                            LEXTRACE("ALIAS ");
1.1.1.2   misho     568:                            LEXRETURN(ALIAS);
1.1       misho     569:                        }
                    570: 
                    571: <GOTDEFS>({PATH}|sudoedit) {
1.1.1.4   misho     572:                            /* XXX - no way to specify digest for command */
1.1       misho     573:                            /* no command args allowed for Defaults!/path */
1.1.1.4   misho     574:                            if (!fill_cmnd(sudoerstext, sudoersleng))
1.1       misho     575:                                yyterminate();
                    576:                            LEXTRACE("COMMAND ");
1.1.1.2   misho     577:                            LEXRETURN(COMMAND);
1.1       misho     578:                        }
                    579: 
1.1.1.4   misho     580: sha224                 {
                    581:                            digest_len = SHA224_DIGEST_LENGTH;
                    582:                            BEGIN WANTDIGEST;
                    583:                            LEXTRACE("SHA224 ");
                    584:                            LEXRETURN(SHA224);
                    585:                        }
                    586: 
                    587: sha256                 {
                    588:                            digest_len = SHA256_DIGEST_LENGTH;
                    589:                            BEGIN WANTDIGEST;
                    590:                            LEXTRACE("SHA256 ");
                    591:                            LEXRETURN(SHA256);
                    592:                        }
                    593: 
                    594: sha384                 {
                    595:                            digest_len = SHA384_DIGEST_LENGTH;
                    596:                            BEGIN WANTDIGEST;
                    597:                            LEXTRACE("SHA384 ");
                    598:                            LEXRETURN(SHA384);
                    599:                        }
                    600: 
                    601: sha512                 {
                    602:                            digest_len = SHA512_DIGEST_LENGTH;
                    603:                            BEGIN WANTDIGEST;
                    604:                            LEXTRACE("SHA512 ");
                    605:                            LEXRETURN(SHA512);
                    606:                        }
                    607: 
1.1       misho     608: sudoedit               {
                    609:                            BEGIN GOTCMND;
                    610:                            LEXTRACE("COMMAND ");
1.1.1.4   misho     611:                            if (!fill_cmnd(sudoerstext, sudoersleng))
1.1       misho     612:                                yyterminate();
                    613:                        }                       /* sudo -e */
                    614: 
                    615: {PATH}                 {
                    616:                            /* directories can't have args... */
1.1.1.4   misho     617:                            if (sudoerstext[sudoersleng - 1] == '/') {
1.1       misho     618:                                LEXTRACE("COMMAND ");
1.1.1.4   misho     619:                                if (!fill_cmnd(sudoerstext, sudoersleng))
1.1       misho     620:                                    yyterminate();
1.1.1.2   misho     621:                                LEXRETURN(COMMAND);
1.1       misho     622:                            } else {
                    623:                                BEGIN GOTCMND;
                    624:                                LEXTRACE("COMMAND ");
1.1.1.4   misho     625:                                if (!fill_cmnd(sudoerstext, sudoersleng))
1.1       misho     626:                                    yyterminate();
                    627:                            }
                    628:                        }                       /* a pathname */
                    629: 
                    630: <INITIAL,GOTDEFS>\" {
                    631:                            LEXTRACE("BEGINSTR ");
1.1.1.4   misho     632:                            sudoerslval.string = NULL;
1.1       misho     633:                            prev_state = YY_START;
                    634:                            BEGIN INSTR;
                    635:                        }
                    636: 
                    637: <INITIAL,GOTDEFS>({ID}|{WORD}) {
                    638:                            /* a word */
1.1.1.4   misho     639:                            if (!fill(sudoerstext, sudoersleng))
1.1       misho     640:                                yyterminate();
                    641:                            LEXTRACE("WORD(5) ");
1.1.1.2   misho     642:                            LEXRETURN(WORD);
1.1       misho     643:                        }
                    644: 
                    645: \(                     {
                    646:                            LEXTRACE("( ");
1.1.1.2   misho     647:                            LEXRETURN('(');
1.1       misho     648:                        }
                    649: 
                    650: \)                     {
                    651:                            LEXTRACE(") ");
1.1.1.2   misho     652:                            LEXRETURN(')');
1.1       misho     653:                        }
                    654: 
                    655: ,                      {
                    656:                            LEXTRACE(", ");
1.1.1.2   misho     657:                            LEXRETURN(',');
1.1       misho     658:                        }                       /* return ',' */
                    659: 
                    660: =                      {
                    661:                            LEXTRACE("= ");
1.1.1.2   misho     662:                            LEXRETURN('=');
1.1       misho     663:                        }                       /* return '=' */
                    664: 
                    665: :                      {
                    666:                            LEXTRACE(": ");
1.1.1.2   misho     667:                            LEXRETURN(':');
1.1       misho     668:                        }                       /* return ':' */
                    669: 
                    670: <*>!+                  {
1.1.1.4   misho     671:                            if (sudoersleng & 1) {
1.1       misho     672:                                LEXTRACE("!");
1.1.1.2   misho     673:                                LEXRETURN('!'); /* return '!' */
1.1       misho     674:                            }
                    675:                        }
                    676: 
                    677: <*>\n                  {
                    678:                            if (YY_START == INSTR) {
                    679:                                LEXTRACE("ERROR ");
1.1.1.2   misho     680:                                LEXRETURN(ERROR);       /* line break in string */
1.1       misho     681:                            }
                    682:                            BEGIN INITIAL;
1.1.1.2   misho     683:                            sudolineno++;
                    684:                            continued = false;
1.1       misho     685:                            LEXTRACE("\n");
1.1.1.2   misho     686:                            LEXRETURN(COMMENT);
1.1       misho     687:                        }                       /* return newline */
                    688: 
                    689: <*>[[:blank:]]+                {                       /* throw away space/tabs */
1.1.1.2   misho     690:                            sawspace = true;    /* but remember for fill_args */
1.1       misho     691:                        }
                    692: 
                    693: <*>\\[[:blank:]]*\n    {
1.1.1.2   misho     694:                            sawspace = true;    /* remember for fill_args */
                    695:                            sudolineno++;
                    696:                            continued = true;
1.1       misho     697:                        }                       /* throw away EOL after \ */
                    698: 
1.1.1.5 ! misho     699: <INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n?       {
        !           700:                            if (sudoerstext[sudoersleng - 1] == '\n') {
        !           701:                                /* comment ending in a newline */
        !           702:                                BEGIN INITIAL;
        !           703:                                sudolineno++;
        !           704:                                continued = false;
        !           705:                            } else if (!feof(yyin)) {
        !           706:                                LEXTRACE("ERROR ");
        !           707:                                LEXRETURN(ERROR);
        !           708:                            }
1.1       misho     709:                            LEXTRACE("#\n");
1.1.1.2   misho     710:                            LEXRETURN(COMMENT);
1.1       misho     711:                        }                       /* comment, not uid/gid */
                    712: 
                    713: <*>.                   {
                    714:                            LEXTRACE("ERROR ");
1.1.1.2   misho     715:                            LEXRETURN(ERROR);
1.1       misho     716:                        }       /* parse error */
                    717: 
                    718: <*><<EOF>>             {
                    719:                            if (YY_START != INITIAL) {
                    720:                                BEGIN INITIAL;
                    721:                                LEXTRACE("ERROR ");
1.1.1.2   misho     722:                                LEXRETURN(ERROR);
1.1       misho     723:                            }
                    724:                            if (!pop_include())
                    725:                                yyterminate();
                    726:                        }
                    727: 
                    728: %%
                    729: struct path_list {
1.1.1.5 ! misho     730:     SLIST_ENTRY(path_list) entries;
1.1       misho     731:     char *path;
                    732: };
                    733: 
1.1.1.5 ! misho     734: SLIST_HEAD(path_list_head, path_list);
        !           735: 
1.1       misho     736: struct include_stack {
                    737:     YY_BUFFER_STATE bs;
                    738:     char *path;
1.1.1.5 ! misho     739:     struct path_list_head more; /* more files in case of includedir */
1.1       misho     740:     int lineno;
1.1.1.2   misho     741:     bool keepopen;
1.1       misho     742: };
                    743: 
1.1.1.5 ! misho     744: /*
        !           745:  * Compare two struct path_list structs in reverse order.
        !           746:  */
1.1       misho     747: static int
                    748: pl_compare(const void *v1, const void *v2)
                    749: {
                    750:     const struct path_list * const *p1 = v1;
                    751:     const struct path_list * const *p2 = v2;
                    752: 
1.1.1.5 ! misho     753:     return strcmp((*p2)->path, (*p1)->path);
1.1       misho     754: }
                    755: 
                    756: static char *
                    757: switch_dir(struct include_stack *stack, char *dirpath)
                    758: {
                    759:     DIR *dir;
1.1.1.5 ! misho     760:     unsigned int i, count = 0;
        !           761:     unsigned int max_paths = 32;
1.1       misho     762:     char *path = NULL;
                    763:     struct dirent *dent;
                    764:     struct stat sb;
1.1.1.5 ! misho     765:     struct path_list *pl, **paths = NULL;
1.1.1.2   misho     766:     debug_decl(switch_dir, SUDO_DEBUG_PARSER)
1.1       misho     767: 
                    768:     if (!(dir = opendir(dirpath))) {
                    769:        if (errno != ENOENT) {
1.1.1.4   misho     770:            warning("%s", dirpath);
                    771:            sudoerserror(NULL);
1.1       misho     772:        }
                    773:        goto done;
                    774:     }
1.1.1.5 ! misho     775:     paths = malloc(sizeof(*paths) * max_paths);
        !           776:     if (paths == NULL) {
        !           777:        closedir(dir);
        !           778:        goto bad;
        !           779:     }
1.1       misho     780:     while ((dent = readdir(dir))) {
                    781:        /* Ignore files that end in '~' or have a '.' in them. */
                    782:        if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
                    783:            || strchr(dent->d_name, '.') != NULL) {
                    784:            continue;
                    785:        }
                    786:        if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
                    787:            closedir(dir);
                    788:            goto bad;
                    789:        }
                    790:        if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
                    791:            efree(path);
                    792:            path = NULL;
                    793:            continue;
                    794:        }
                    795:        pl = malloc(sizeof(*pl));
                    796:        if (pl == NULL)
                    797:            goto bad;
                    798:        pl->path = path;
1.1.1.5 ! misho     799:        if (count >= max_paths) {
        !           800:            struct path_list **tmp;
        !           801:            max_paths <<= 1;
        !           802:            tmp = realloc(paths, sizeof(*paths) * max_paths);
        !           803:            if (tmp == NULL) {
        !           804:                closedir(dir);
        !           805:                goto bad;
        !           806:            }
        !           807:            paths = tmp;
        !           808:        }
        !           809:        paths[count++] = pl;
1.1.1.4   misho     810:        path = NULL;
1.1       misho     811:     }
                    812:     closedir(dir);
                    813: 
                    814:     if (count == 0)
                    815:        goto done;
                    816: 
1.1.1.5 ! misho     817:     /* Sort the list as an array in reverse order. */
        !           818:     qsort(paths, count, sizeof(*paths), pl_compare);
        !           819: 
        !           820:     /* Build up the list in sorted order. */
1.1       misho     821:     for (i = 0; i < count; i++) {
1.1.1.5 ! misho     822:        SLIST_INSERT_HEAD(&stack->more, paths[i], entries);
1.1       misho     823:     }
                    824: 
                    825:     /* Pull out the first element for parsing, leave the rest for later. */
1.1.1.5 ! misho     826:     pl = SLIST_FIRST(&stack->more);
        !           827:     SLIST_REMOVE_HEAD(&stack->more, entries);
        !           828:     path = pl->path;
        !           829:     efree(pl);
1.1       misho     830: done:
1.1.1.5 ! misho     831:     efree(paths);
1.1       misho     832:     efree(dirpath);
1.1.1.2   misho     833:     debug_return_str(path);
1.1       misho     834: bad:
1.1.1.5 ! misho     835:     for (i = 0; i < count; i++) {
        !           836:        efree(paths[i]->path);
        !           837:        efree(paths[i]);
1.1       misho     838:     }
1.1.1.5 ! misho     839:     efree(paths);
1.1       misho     840:     efree(dirpath);
                    841:     efree(path);
1.1.1.2   misho     842:     debug_return_str(NULL);
1.1       misho     843: }
                    844: 
                    845: #define MAX_SUDOERS_DEPTH      128
                    846: #define SUDOERS_STACK_INCREMENT        16
                    847: 
                    848: static size_t istacksize, idepth;
                    849: static struct include_stack *istack;
1.1.1.2   misho     850: static bool keepopen;
1.1       misho     851: 
                    852: void
                    853: init_lexer(void)
                    854: {
                    855:     struct path_list *pl;
1.1.1.2   misho     856:     debug_decl(init_lexer, SUDO_DEBUG_PARSER)
1.1       misho     857: 
                    858:     while (idepth) {
                    859:        idepth--;
1.1.1.5 ! misho     860:        while ((pl = SLIST_FIRST(&istack[idepth].more)) != NULL) {
        !           861:            SLIST_REMOVE_HEAD(&istack[idepth].more, entries);
1.1       misho     862:            efree(pl->path);
                    863:            efree(pl);
                    864:        }
                    865:        efree(istack[idepth].path);
                    866:        if (idepth && !istack[idepth].keepopen)
                    867:            fclose(istack[idepth].bs->yy_input_file);
1.1.1.4   misho     868:        sudoers_delete_buffer(istack[idepth].bs);
1.1       misho     869:     }
                    870:     efree(istack);
                    871:     istack = NULL;
                    872:     istacksize = idepth = 0;
                    873:     sudolineno = 1;
1.1.1.2   misho     874:     keepopen = false;
                    875:     sawspace = false;
                    876:     continued = false;
1.1       misho     877:     prev_state = INITIAL;
1.1.1.2   misho     878: 
                    879:     debug_return;
1.1       misho     880: }
                    881: 
1.1.1.2   misho     882: static bool
                    883: _push_include(char *path, bool isdir)
1.1       misho     884: {
                    885:     struct path_list *pl;
                    886:     FILE *fp;
1.1.1.2   misho     887:     debug_decl(_push_include, SUDO_DEBUG_PARSER)
1.1       misho     888: 
                    889:     /* push current state onto stack */
                    890:     if (idepth >= istacksize) {
1.1.1.5 ! misho     891:        struct include_stack *new_istack;
        !           892: 
1.1       misho     893:        if (idepth > MAX_SUDOERS_DEPTH) {
1.1.1.4   misho     894:            sudoerserror(N_("too many levels of includes"));
1.1.1.2   misho     895:            debug_return_bool(false);
1.1       misho     896:        }
                    897:        istacksize += SUDOERS_STACK_INCREMENT;
1.1.1.5 ! misho     898:        new_istack = (struct include_stack *) realloc(istack,
1.1       misho     899:            sizeof(*istack) * istacksize);
1.1.1.5 ! misho     900:        if (new_istack == NULL) {
1.1.1.4   misho     901:            warning(NULL);
                    902:            sudoerserror(NULL);
1.1.1.2   misho     903:            debug_return_bool(false);
1.1       misho     904:        }
1.1.1.5 ! misho     905:        istack = new_istack;
1.1       misho     906:     }
1.1.1.5 ! misho     907:     SLIST_INIT(&istack[idepth].more);
1.1       misho     908:     if (isdir) {
1.1.1.2   misho     909:        struct stat sb;
                    910:        switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) {
                    911:            case SUDO_PATH_SECURE:
                    912:                break;
                    913:            case SUDO_PATH_MISSING:
                    914:                debug_return_bool(false);
                    915:            case SUDO_PATH_BAD_TYPE:
                    916:                errno = ENOTDIR;
                    917:                if (sudoers_warnings) {
                    918:                    warning("%s", path);
                    919:                }
                    920:                debug_return_bool(false);
                    921:            case SUDO_PATH_WRONG_OWNER:
                    922:                if (sudoers_warnings) {
1.1.1.5 ! misho     923:                    warningx(U_("%s is owned by uid %u, should be %u"),   
1.1.1.2   misho     924:                        path, (unsigned int) sb.st_uid,
                    925:                        (unsigned int) sudoers_uid);
                    926:                }
                    927:                debug_return_bool(false);
                    928:            case SUDO_PATH_WORLD_WRITABLE:
                    929:                if (sudoers_warnings) {
1.1.1.5 ! misho     930:                    warningx(U_("%s is world writable"), path);
1.1.1.2   misho     931:                }
                    932:                debug_return_bool(false);
                    933:            case SUDO_PATH_GROUP_WRITABLE:
                    934:                if (sudoers_warnings) {
1.1.1.5 ! misho     935:                    warningx(U_("%s is owned by gid %u, should be %u"),
1.1.1.2   misho     936:                        path, (unsigned int) sb.st_gid,
                    937:                        (unsigned int) sudoers_gid);
                    938:                }
                    939:                debug_return_bool(false);
                    940:            default:
                    941:                /* NOTREACHED */
                    942:                debug_return_bool(false);
                    943:        }
1.1       misho     944:        if (!(path = switch_dir(&istack[idepth], path))) {
1.1.1.4   misho     945:            /* switch_dir() called sudoerserror() for us */
1.1.1.2   misho     946:            debug_return_bool(false);
1.1       misho     947:        }
1.1.1.2   misho     948:        while ((fp = open_sudoers(path, false, &keepopen)) == NULL) {
1.1       misho     949:            /* Unable to open path in includedir, go to next one, if any. */
                    950:            efree(path);
1.1.1.5 ! misho     951:            if ((pl = SLIST_FIRST(&istack[idepth].more)) == NULL)
1.1.1.2   misho     952:                debug_return_bool(false);
1.1.1.5 ! misho     953:            SLIST_REMOVE_HEAD(&istack[idepth].more, entries);
1.1       misho     954:            path = pl->path;
                    955:            efree(pl);
                    956:        }
                    957:     } else {
1.1.1.2   misho     958:        if ((fp = open_sudoers(path, true, &keepopen)) == NULL) {
1.1.1.3   misho     959:            /* The error was already printed by open_sudoers() */
1.1.1.4   misho     960:            sudoerserror(NULL);
1.1.1.2   misho     961:            debug_return_bool(false);
1.1       misho     962:        }
                    963:     }
                    964:     /* Push the old (current) file and open the new one. */
                    965:     istack[idepth].path = sudoers; /* push old path */
                    966:     istack[idepth].bs = YY_CURRENT_BUFFER;
                    967:     istack[idepth].lineno = sudolineno;
                    968:     istack[idepth].keepopen = keepopen;
                    969:     idepth++;
                    970:     sudolineno = 1;
                    971:     sudoers = path;
1.1.1.4   misho     972:     sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE));
1.1       misho     973: 
1.1.1.2   misho     974:     debug_return_bool(true);
1.1       misho     975: }
                    976: 
1.1.1.2   misho     977: static bool
1.1       misho     978: pop_include(void)
                    979: {
                    980:     struct path_list *pl;
                    981:     FILE *fp;
1.1.1.2   misho     982:     debug_decl(pop_include, SUDO_DEBUG_PARSER)
1.1       misho     983: 
                    984:     if (idepth == 0)
1.1.1.2   misho     985:        debug_return_bool(false);
1.1       misho     986: 
                    987:     if (!keepopen)
                    988:        fclose(YY_CURRENT_BUFFER->yy_input_file);
1.1.1.4   misho     989:     sudoers_delete_buffer(YY_CURRENT_BUFFER);
1.1       misho     990:     /* If we are in an include dir, move to the next file. */
1.1.1.5 ! misho     991:     while ((pl = SLIST_FIRST(&istack[idepth - 1].more)) != NULL) {
        !           992:        SLIST_REMOVE_HEAD(&istack[idepth - 1].more, entries);
1.1.1.2   misho     993:        fp = open_sudoers(pl->path, false, &keepopen);
1.1       misho     994:        if (fp != NULL) {
                    995:            efree(sudoers);
                    996:            sudoers = pl->path;
                    997:            sudolineno = 1;
1.1.1.4   misho     998:            sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE));
1.1       misho     999:            efree(pl);
                   1000:            break;
                   1001:        }
                   1002:        /* Unable to open path in include dir, go to next one. */
                   1003:        efree(pl->path);
                   1004:        efree(pl);
                   1005:     }
                   1006:     /* If no path list, just pop the last dir on the stack. */
                   1007:     if (pl == NULL) {
                   1008:        idepth--;
1.1.1.4   misho    1009:        sudoers_switch_to_buffer(istack[idepth].bs);
1.1       misho    1010:        efree(sudoers);
                   1011:        sudoers = istack[idepth].path;
                   1012:        sudolineno = istack[idepth].lineno;
                   1013:        keepopen = istack[idepth].keepopen;
                   1014:     }
1.1.1.2   misho    1015:     debug_return_bool(true);
1.1       misho    1016: }
                   1017: 
                   1018: static char *
                   1019: parse_include(char *base)
                   1020: {
1.1.1.2   misho    1021:     char *cp, *ep, *path, *pp;
                   1022:     int dirlen = 0, len = 0, subst = 0;
1.1       misho    1023:     size_t shost_len = 0;
1.1.1.2   misho    1024:     debug_decl(parse_include, SUDO_DEBUG_PARSER)
1.1       misho    1025: 
                   1026:     /* Pull out path from #include line. */
                   1027:     cp = base + sizeof("#include");
                   1028:     if (*cp == 'i')
                   1029:        cp += 3; /* includedir */
                   1030:     while (isblank((unsigned char) *cp))
                   1031:        cp++;
                   1032:     ep = cp;
                   1033:     while (*ep != '\0' && !isspace((unsigned char) *ep)) {
                   1034:        if (ep[0] == '%' && ep[1] == 'h') {
                   1035:            shost_len = strlen(user_shost);
                   1036:            len += shost_len - 2;
                   1037:            subst = 1;
                   1038:        }
                   1039:        ep++;
                   1040:     }
                   1041: 
1.1.1.2   misho    1042:     /* Relative paths are located in the same dir as the sudoers file. */
                   1043:     if (*cp != '/') {
                   1044:        char *dirend = strrchr(sudoers, '/');
                   1045:        if (dirend != NULL)
                   1046:            dirlen = (int)(dirend - sudoers) + 1;
                   1047:     }
                   1048: 
                   1049:     /* Make a copy of the fully-qualified path and return it. */
1.1       misho    1050:     len += (int)(ep - cp);
1.1.1.2   misho    1051:     path = pp = malloc(len + dirlen + 1);
                   1052:     if (path == NULL) {
1.1.1.4   misho    1053:        warning(NULL);
                   1054:        sudoerserror(NULL);
1.1.1.2   misho    1055:        debug_return_str(NULL);
                   1056:     }
                   1057:     if (dirlen) {
                   1058:        memcpy(path, sudoers, dirlen);
                   1059:        pp += dirlen;
1.1       misho    1060:     }
                   1061:     if (subst) {
                   1062:        /* substitute for %h */
                   1063:        while (cp < ep) {
                   1064:            if (cp[0] == '%' && cp[1] == 'h') {
                   1065:                memcpy(pp, user_shost, shost_len);
                   1066:                pp += shost_len;
                   1067:                cp += 2;
                   1068:                continue;
                   1069:            }
                   1070:            *pp++ = *cp++;
                   1071:        }
                   1072:        *pp = '\0';
                   1073:     } else {
1.1.1.2   misho    1074:        memcpy(pp, cp, len);
                   1075:        pp[len] = '\0';
1.1       misho    1076:     }
                   1077: 
                   1078:     /* Push any excess characters (e.g. comment, newline) back to the lexer */
                   1079:     if (*ep != '\0')
                   1080:        yyless((int)(ep - base));
                   1081: 
1.1.1.2   misho    1082:     debug_return_str(path);
1.1       misho    1083: }
                   1084: 
                   1085: #ifdef TRACELEXER
1.1.1.3   misho    1086: int
1.1       misho    1087: sudoers_trace_print(const char *msg)
                   1088: {
                   1089:     return fputs(msg, stderr);
                   1090: }
1.1.1.2   misho    1091: #else
1.1.1.3   misho    1092: int
1.1.1.2   misho    1093: sudoers_trace_print(const char *msg)
                   1094: {
                   1095:     static bool initialized;
                   1096:     static struct lbuf lbuf;
                   1097: 
                   1098:     if (!initialized) {
                   1099:        initialized = true;
                   1100:        lbuf_init(&lbuf, NULL, 0, NULL, 0);
                   1101:     }
                   1102: 
                   1103:     lbuf_append(&lbuf, "%s", msg);
                   1104:     /* XXX - assumes a final newline */
                   1105:     if (strchr(msg, '\n') != NULL)
                   1106:     {
                   1107:        sudo_debug_printf2(NULL, NULL, 0, SUDO_DEBUG_PARSER|SUDO_DEBUG_DEBUG,
                   1108:            "%s:%d %s", sudoers, sudolineno, lbuf.buf);
                   1109:        lbuf.len = 0;
                   1110:     }
                   1111:     return 0;
                   1112: }
1.1       misho    1113: #endif /* TRACELEXER */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>