1 %{ 2 /* 3 * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com> 4 * 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. 8 * 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. 16 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 17 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 18 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 * 20 * Sponsored in part by the Defense Advanced Research Projects 21 * Agency (DARPA) and Air Force Research Laboratory, Air Force 22 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 23 */ 24 25 #include "config.h" 26 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <stdio.h> 30 #ifdef STDC_HEADERS 31 # include <stdlib.h> 32 # include <stddef.h> 33 #else 34 # ifdef HAVE_STDLIB_H 35 # include <stdlib.h> 36 # endif 37 #endif /* STDC_HEADERS */ 38 #ifdef HAVE_STRING_H 39 # include <string.h> 40 #else 41 # ifdef HAVE_STRINGS_H 42 # include <strings.h> 43 # endif 44 #endif /* HAVE_STRING_H */ 45 #ifdef HAVE_UNISTD_H 46 # include <unistd.h> 47 #endif /* HAVE_UNISTD_H */ 48 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) 49 # include <malloc.h> 50 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ 51 #include <ctype.h> 52 #include "sudo.h" 53 #include "parse.h" 54 #include <sudo.tab.h> 55 56 #ifndef lint 57 static const char rcsid[] = "$Sudo: parse.lex,v 1.132 2004/05/17 20:51:13 millert Exp $"; 58 #endif /* lint */ 59 60 #undef yywrap /* guard against a yywrap macro */ 61 62 extern YYSTYPE yylval; 63 extern int clearaliases; 64 int sudolineno = 1; 65 static int sawspace = 0; 66 static int arg_len = 0; 67 static int arg_size = 0; 68 69 static void fill __P((char *, int)); 70 static void fill_cmnd __P((char *, int)); 71 static void fill_args __P((char *, int, int)); 72 extern void reset_aliases __P((void)); 73 extern void yyerror __P((char *)); 74 75 /* realloc() to size + COMMANDARGINC to make room for command args */ 76 #define COMMANDARGINC 64 77 78 #ifdef TRACELEXER 79 #define LEXTRACE(msg) fputs(msg, stderr) 80 #else 81 #define LEXTRACE(msg) 82 #endif 83 %} 84 85 OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) 86 DOTTEDQUAD {OCTET}(\.{OCTET}){3} 87 HOSTNAME [[:alnum:]_-]+ 88 WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+ 89 ENVAR ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])* 90 DEFVAR [a-z_]+ 91 92 /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */ 93 %s GOTRUNAS 94 %s GOTDEFS 95 %x GOTCMND 96 %x STARTDEFS 97 %x INDEFS 98 99 %% 100 <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS; 101 102 <STARTDEFS>{DEFVAR} { 103 BEGIN INDEFS; 104 LEXTRACE("DEFVAR "); 105 fill(yytext, yyleng); 106 return(DEFVAR); 107 } 108 109 <INDEFS>{ 110 , { 111 BEGIN STARTDEFS; 112 LEXTRACE(", "); 113 return(','); 114 } /* return ',' */ 115 116 = { 117 LEXTRACE("= "); 118 return('='); 119 } /* return '=' */ 120 121 \+= { 122 LEXTRACE("+= "); 123 return('+'); 124 } /* return '+' */ 125 126 -= { 127 LEXTRACE("-= "); 128 return('-'); 129 } /* return '-' */ 130 131 \"([^\"]|\\\")+\" { 132 LEXTRACE("WORD(1) "); 133 fill(yytext + 1, yyleng - 2); 134 return(WORD); 135 } 136 137 {ENVAR} { 138 LEXTRACE("WORD(2) "); 139 fill(yytext, yyleng); 140 return(WORD); 141 } 142 } 143 144 <GOTCMND>{ 145 \\[\*\?\[\]\!] { 146 /* quoted fnmatch glob char, pass verbatim */ 147 LEXTRACE("QUOTEDCHAR "); 148 fill_args(yytext, 2, sawspace); 149 sawspace = FALSE; 150 } 151 152 \\[:\\,= \t#] { 153 /* quoted sudoers special char, strip backslash */ 154 LEXTRACE("QUOTEDCHAR "); 155 fill_args(yytext + 1, 1, sawspace); 156 sawspace = FALSE; 157 } 158 159 [#:\,=\n] { 160 BEGIN INITIAL; 161 unput(*yytext); 162 return(COMMAND); 163 } /* end of command line args */ 164 165 [^\\:, \t\n]+ { 166 LEXTRACE("ARG "); 167 fill_args(yytext, yyleng, sawspace); 168 sawspace = FALSE; 169 } /* a command line arg */ 170 } 171 172 <INITIAL>^Defaults[:@>]? { 173 BEGIN GOTDEFS; 174 switch (yytext[8]) { 175 case ':': 176 LEXTRACE("DEFAULTS_USER "); 177 return(DEFAULTS_USER); 178 case '>': 179 LEXTRACE("DEFAULTS_RUNAS "); 180 return(DEFAULTS_RUNAS); 181 case '@': 182 LEXTRACE("DEFAULTS_HOST "); 183 return(DEFAULTS_HOST); 184 default: 185 LEXTRACE("DEFAULTS "); 186 return(DEFAULTS); 187 } 188 } 189 190 <INITIAL>^(Host|Cmnd|User|Runas)_Alias { 191 fill(yytext, yyleng); 192 switch (*yytext) { 193 case 'H': 194 LEXTRACE("HOSTALIAS "); 195 return(HOSTALIAS); 196 case 'C': 197 LEXTRACE("CMNDALIAS "); 198 return(CMNDALIAS); 199 case 'U': 200 LEXTRACE("USERALIAS "); 201 return(USERALIAS); 202 case 'R': 203 LEXTRACE("RUNASALIAS "); 204 BEGIN GOTRUNAS; 205 return(RUNASALIAS); 206 } 207 } 208 209 NOPASSWD[[:blank:]]*: { 210 /* cmnd does not require passwd for this user */ 211 LEXTRACE("NOPASSWD "); 212 return(NOPASSWD); 213 } 214 215 PASSWD[[:blank:]]*: { 216 /* cmnd requires passwd for this user */ 217 LEXTRACE("PASSWD "); 218 return(PASSWD); 219 } 220 221 NOEXEC[[:blank:]]*: { 222 LEXTRACE("NOEXEC "); 223 return(NOEXEC); 224 } 225 226 EXEC[[:blank:]]*: { 227 LEXTRACE("EXEC "); 228 return(EXEC); 229 } 230 231 \+{WORD} { 232 /* netgroup */ 233 fill(yytext, yyleng); 234 LEXTRACE("NETGROUP "); 235 return(NETGROUP); 236 } 237 238 \%{WORD} { 239 /* UN*X group */ 240 fill(yytext, yyleng); 241 LEXTRACE("GROUP "); 242 return(USERGROUP); 243 } 244 245 {DOTTEDQUAD}(\/{DOTTEDQUAD})? { 246 fill(yytext, yyleng); 247 LEXTRACE("NTWKADDR "); 248 return(NTWKADDR); 249 } 250 251 {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) { 252 fill(yytext, yyleng); 253 LEXTRACE("NTWKADDR "); 254 return(NTWKADDR); 255 } 256 257 <INITIAL>\( { 258 BEGIN GOTRUNAS; 259 LEXTRACE("RUNAS "); 260 return (RUNAS); 261 } 262 263 [[:upper:]][[:upper:][:digit:]_]* { 264 if (strcmp(yytext, "ALL") == 0) { 265 LEXTRACE("ALL "); 266 return(ALL); 267 } else { 268 fill(yytext, yyleng); 269 LEXTRACE("ALIAS "); 270 return(ALIAS); 271 } 272 } 273 274 <GOTRUNAS>(#[0-9-]+|{WORD}) { 275 /* username/uid that user can run command as */ 276 fill(yytext, yyleng); 277 LEXTRACE("WORD(3) "); 278 return(WORD); 279 } 280 281 <GOTRUNAS>\) { 282 BEGIN INITIAL; 283 } 284 285 sudoedit { 286 BEGIN GOTCMND; 287 LEXTRACE("COMMAND "); 288 fill_cmnd(yytext, yyleng); 289 } /* sudo -e */ 290 291 \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ { 292 /* directories can't have args... */ 293 if (yytext[yyleng - 1] == '/') { 294 LEXTRACE("COMMAND "); 295 fill_cmnd(yytext, yyleng); 296 return(COMMAND); 297 } else { 298 BEGIN GOTCMND; 299 LEXTRACE("COMMAND "); 300 fill_cmnd(yytext, yyleng); 301 } 302 } /* a pathname */ 303 304 <INITIAL,GOTDEFS>{WORD} { 305 /* a word */ 306 fill(yytext, yyleng); 307 LEXTRACE("WORD(4) "); 308 return(WORD); 309 } 310 311 , { 312 LEXTRACE(", "); 313 return(','); 314 } /* return ',' */ 315 316 = { 317 LEXTRACE("= "); 318 return('='); 319 } /* return '=' */ 320 321 : { 322 LEXTRACE(": "); 323 return(':'); 324 } /* return ':' */ 325 326 <*>!+ { 327 if (yyleng % 2 == 1) 328 return('!'); /* return '!' */ 329 } 330 331 <*>\n { 332 BEGIN INITIAL; 333 ++sudolineno; 334 LEXTRACE("\n"); 335 return(COMMENT); 336 } /* return newline */ 337 338 <*>[[:blank:]]+ { /* throw away space/tabs */ 339 sawspace = TRUE; /* but remember for fill_args */ 340 } 341 342 <*>\\[[:blank:]]*\n { 343 sawspace = TRUE; /* remember for fill_args */ 344 ++sudolineno; 345 LEXTRACE("\n\t"); 346 } /* throw away EOL after \ */ 347 348 <INITIAL,STARTDEFS,INDEFS>#.*\n { 349 BEGIN INITIAL; 350 ++sudolineno; 351 LEXTRACE("\n"); 352 return(COMMENT); 353 } /* return comments */ 354 355 <*>. { 356 LEXTRACE("ERROR "); 357 return(ERROR); 358 } /* parse error */ 359 360 <*><<EOF>> { 361 if (YY_START != INITIAL) { 362 BEGIN INITIAL; 363 LEXTRACE("ERROR "); 364 return(ERROR); 365 } 366 yyterminate(); 367 } 368 369 %% 370 static void 371 fill(s, len) 372 char *s; 373 int len; 374 { 375 int i, j; 376 377 yylval.string = (char *) malloc(len + 1); 378 if (yylval.string == NULL) { 379 yyerror("unable to allocate memory"); 380 return; 381 } 382 383 /* Copy the string and collapse any escaped characters. */ 384 for (i = 0, j = 0; i < len; i++, j++) { 385 if (s[i] == '\\' && i != len - 1) 386 yylval.string[j] = s[++i]; 387 else 388 yylval.string[j] = s[i]; 389 } 390 yylval.string[j] = '\0'; 391 } 392 393 static void 394 fill_cmnd(s, len) 395 char *s; 396 int len; 397 { 398 arg_len = arg_size = 0; 399 400 yylval.command.cmnd = (char *) malloc(++len); 401 if (yylval.command.cmnd == NULL) { 402 yyerror("unable to allocate memory"); 403 return; 404 } 405 406 /* copy the string and NULL-terminate it (escapes handled by fnmatch) */ 407 (void) strlcpy(yylval.command.cmnd, s, len); 408 409 yylval.command.args = NULL; 410 } 411 412 static void 413 fill_args(s, len, addspace) 414 char *s; 415 int len; 416 int addspace; 417 { 418 int new_len; 419 char *p; 420 421 if (yylval.command.args == NULL) { 422 addspace = 0; 423 new_len = len; 424 } else 425 new_len = arg_len + len + addspace; 426 427 if (new_len >= arg_size) { 428 /* Allocate more space than we need for subsequent args */ 429 while (new_len >= (arg_size += COMMANDARGINC)) 430 ; 431 432 p = yylval.command.args ? 433 (char *) realloc(yylval.command.args, arg_size) : 434 (char *) malloc(arg_size); 435 if (p == NULL) { 436 if (yylval.command.args != NULL) 437 free(yylval.command.args); 438 yyerror("unable to allocate memory"); 439 return; 440 } else 441 yylval.command.args = p; 442 } 443 444 /* Efficiently append the arg (with a leading space if needed). */ 445 p = yylval.command.args + arg_len; 446 if (addspace) 447 *p++ = ' '; 448 if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) 449 yyerror("fill_args: buffer overflow"); /* paranoia */ 450 arg_len = new_len; 451 } 452 453 int 454 yywrap() 455 { 456 457 /* Free space used by the aliases unless called by testsudoers. */ 458 if (clearaliases) 459 reset_aliases(); 460 461 return(TRUE); 462 } 463