%{ /* * Copyright (c) 1996, 1998, 1999 Todd C. Miller * All rights reserved. * * This code is derived from software contributed by Chris Jepeway * * * This code is derived from software contributed by Chris Jepeway * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 4. Products derived from this software may not be called "Sudo" nor * may "Sudo" appear in their names without specific prior written * permission from the author. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #ifdef STDC_HEADERS #include #endif /* STDC_HEADERS */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_STRING_H #include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) #include #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ #include #include #include #include "sudo.h" #include "parse.h" #include "sudo.tab.h" #ifndef lint static const char rcsid[] = "$Sudo: parse.lex,v 1.110 1999/12/06 00:05:53 millert Exp $"; #endif /* lint */ #undef yywrap /* guard against a yywrap macro */ extern YYSTYPE yylval; extern int clearaliases; int sudolineno = 1; static int sawspace = 0; static int arg_len = 0; static int arg_size = 0; static void fill __P((char *, int)); static void fill_cmnd __P((char *, int)); static void fill_args __P((char *, int, int)); extern void reset_aliases __P((void)); extern void yyerror __P((char *)); /* realloc() to size + COMMANDARGINC to make room for command args */ #define COMMANDARGINC 64 #ifdef TRACELEXER #define LEXTRACE(msg) fputs(msg, stderr) #else #define LEXTRACE(msg) #endif %} OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) DOTTEDQUAD {OCTET}(\.{OCTET}){3} HOSTNAME [[:alnum:]_-]+ WORD ([^@!=:,\(\) \t\n\\]|\\[^\n])+ %s GOTCMND %s GOTRUNAS %s GOTDEFS %% [ \t]+ { /* throw away space/tabs */ sawspace = TRUE; /* but remember for fill_args */ } \\[ \t]*\n { sawspace = TRUE; /* remember for fill_args */ ++sudolineno; LEXTRACE("\n\t"); } /* throw away EOL after \ */ \\[:\,=\\ \t] { LEXTRACE("QUOTEDCHAR "); fill_args(yytext + 1, 1, sawspace); sawspace = FALSE; } \"([^\"]|\\\")+\" { LEXTRACE("WORD(1) "); fill(yytext + 1, yyleng - 2); return(WORD); } (#.*)?\n { BEGIN INITIAL; ++sudolineno; LEXTRACE("\n"); return(COMMENT); } [:\,=\n] { BEGIN INITIAL; unput(*yytext); return(COMMAND); } /* end of command line args */ \n { ++sudolineno; LEXTRACE("\n"); BEGIN INITIAL; return(COMMENT); } /* return newline */ #.*\n { ++sudolineno; LEXTRACE("\n"); return(COMMENT); } /* return comments */ [^\\:, \t\n]+ { LEXTRACE("ARG "); fill_args(yytext, yyleng, sawspace); sawspace = FALSE; } /* a command line arg */ , { LEXTRACE(", "); return(','); } /* return ',' */ !+ { if (yyleng % 2 == 1) return('!'); /* return '!' */ } = { LEXTRACE("= "); return('='); } /* return '=' */ : { LEXTRACE(": "); return(':'); } /* return ':' */ NOPASSWD[[:blank:]]*: { /* cmnd does not require passwd for this user */ LEXTRACE("NOPASSWD "); return(NOPASSWD); } PASSWD[[:blank:]]*: { /* cmnd requires passwd for this user */ LEXTRACE("PASSWD "); return(PASSWD); } \+{WORD} { /* netgroup */ fill(yytext, yyleng); LEXTRACE("NETGROUP "); return(NETGROUP); } \%{WORD} { /* UN*X group */ fill(yytext, yyleng); LEXTRACE("GROUP "); return(USERGROUP); } {DOTTEDQUAD}(\/{DOTTEDQUAD})? { fill(yytext, yyleng); LEXTRACE("NTWKADDR "); return(NTWKADDR); } {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) { fill(yytext, yyleng); LEXTRACE("NTWKADDR "); return(NTWKADDR); } [[:alpha:]][[:alnum:]_-]*(\.{HOSTNAME})+ { fill(yytext, yyleng); LEXTRACE("FQHOST "); return(FQHOST); } \( { BEGIN GOTRUNAS; LEXTRACE("RUNAS "); return (RUNAS); } [[:upper:]][[:upper:][:digit:]_]* { /* Runas_Alias user can run command as or ALL */ if (strcmp(yytext, "ALL") == 0) { LEXTRACE("ALL "); return(ALL); } else { fill(yytext, yyleng); LEXTRACE("ALIAS "); return(ALIAS); } } #?{WORD} { /* username/uid that user can run command as */ fill(yytext, yyleng); LEXTRACE("WORD(2) "); return(WORD); } \) { BEGIN INITIAL; } [[:upper:]][[:upper:][:digit:]_]* { if (strcmp(yytext, "ALL") == 0) { LEXTRACE("ALL "); return(ALL); } else { fill(yytext, yyleng); LEXTRACE("ALIAS "); return(ALIAS); } } {WORD} { LEXTRACE("WORD(3) "); fill(yytext, yyleng); return(WORD); } ^Defaults[:@]? { BEGIN GOTDEFS; if (yyleng == 9) { switch (yytext[8]) { case ':' : LEXTRACE("DEFAULTS_USER "); return(DEFAULTS_USER); case '@' : LEXTRACE("DEFAULTS_HOST "); return(DEFAULTS_HOST); } } else { LEXTRACE("DEFAULTS "); return(DEFAULTS); } } ^(Host|Cmnd|User|Runas)_Alias { fill(yytext, yyleng); if (*yytext == 'H') { LEXTRACE("HOSTALIAS "); return(HOSTALIAS); } if (*yytext == 'C') { LEXTRACE("CMNDALIAS "); return(CMNDALIAS); } if (*yytext == 'U') { LEXTRACE("USERALIAS "); return(USERALIAS); } if (*yytext == 'R') { LEXTRACE("RUNASALIAS "); BEGIN GOTRUNAS; return(RUNASALIAS); } } \/[^\,:=\\ \t\n#]+ { /* directories can't have args... */ if (yytext[yyleng - 1] == '/') { LEXTRACE("COMMAND "); fill_cmnd(yytext, yyleng); return(COMMAND); } else { BEGIN GOTCMND; LEXTRACE("COMMAND "); fill_cmnd(yytext, yyleng); } } /* a pathname */ {WORD} { /* a word */ fill(yytext, yyleng); LEXTRACE("WORD(4) "); return(WORD); } . { LEXTRACE("ERROR "); return(ERROR); } /* parse error */ %% static void fill(s, len) char *s; int len; { int i, j; yylval.string = (char *) malloc(len + 1); if (yylval.string == NULL) yyerror("unable to allocate memory"); /* Copy the string and collapse any escaped characters. */ for (i = 0, j = 0; i < len; i++, j++) { if (s[i] == '\\' && i != len - 1) yylval.string[j] = s[++i]; else yylval.string[j] = s[i]; } yylval.string[j] = '\0'; } static void fill_cmnd(s, len) char *s; int len; { arg_len = arg_size = 0; yylval.command.cmnd = (char *) malloc(len + 1); if (yylval.command.cmnd == NULL) yyerror("unable to allocate memory"); /* copy the string and NULL-terminate it */ (void) strncpy(yylval.command.cmnd, s, len); yylval.command.cmnd[len] = '\0'; yylval.command.args = NULL; } static void fill_args(s, len, addspace) char *s; int len; int addspace; { int new_len; char *p; /* * If first arg, malloc() some room, else if we don't * have enough space realloc() some more. */ if (yylval.command.args == NULL) { addspace = 0; new_len = len; while (new_len >= (arg_size += COMMANDARGINC)) ; yylval.command.args = (char *) malloc(arg_size); if (yylval.command.args == NULL) yyerror("unable to allocate memory"); } else { new_len = arg_len + len + addspace; if (new_len >= arg_size) { /* Allocate more space than we need for subsequent args */ while (new_len >= (arg_size += COMMANDARGINC)) ; if ((p = (char *) realloc(yylval.command.args, arg_size)) == NULL) { free(yylval.command.args); yyerror("unable to allocate memory"); } else yylval.command.args = p; } } /* Efficiently append the arg (with a leading space if needed). */ p = yylval.command.args + arg_len; if (addspace) *p++ = ' '; (void) strcpy(p, s); arg_len = new_len; } int yywrap() { /* Free space used by the aliases unless called by testsudoers. */ if (clearaliases) reset_aliases(); return(TRUE); }