version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.4, 2013/07/22 10:46:12
|
Line 1
|
Line 1
|
%{ |
%{ |
/* |
/* |
* Copyright (c) 1996, 1998-2005, 2007-2011 | * Copyright (c) 1996, 1998-2005, 2007-2013 |
* Todd C. Miller <Todd.Miller@courtesan.com> |
* Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
Line 26
|
Line 26
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
Line 43
|
Line 42
|
#ifdef HAVE_STRINGS_H |
#ifdef HAVE_STRINGS_H |
# include <strings.h> |
# include <strings.h> |
#endif /* HAVE_STRINGS_H */ |
#endif /* HAVE_STRINGS_H */ |
|
#if defined(HAVE_STDINT_H) |
|
# include <stdint.h> |
|
#elif defined(HAVE_INTTYPES_H) |
|
# include <inttypes.h> |
|
#endif |
#ifdef HAVE_UNISTD_H |
#ifdef HAVE_UNISTD_H |
# include <unistd.h> |
# include <unistd.h> |
#endif /* HAVE_UNISTD_H */ |
#endif /* HAVE_UNISTD_H */ |
Line 71
|
Line 75
|
#include "parse.h" |
#include "parse.h" |
#include "toke.h" |
#include "toke.h" |
#include <gram.h> |
#include <gram.h> |
|
#include "lbuf.h" |
|
#include "sha2.h" |
|
#include "secure_path.h" |
|
|
extern YYSTYPE yylval; | extern YYSTYPE sudoerslval; |
extern int parse_error; | extern bool parse_error; |
| extern bool sudoers_warnings; |
int sudolineno; |
int sudolineno; |
|
int last_token; |
char *sudoers; |
char *sudoers; |
|
|
static int continued, prev_state, sawspace; | /* Default sudoers path, mode and owner (may be set via sudo.conf) */ |
| const char *sudoers_file = _PATH_SUDOERS; |
| mode_t sudoers_mode = SUDOERS_MODE; |
| uid_t sudoers_uid = SUDOERS_UID; |
| gid_t sudoers_gid = SUDOERS_GID; |
|
|
static int _push_include(char *, int); | static bool continued, sawspace; |
static int pop_include(void); | static int prev_state; |
| static int digest_len; |
| |
| static bool _push_include(char *, bool); |
| static bool pop_include(void); |
static char *parse_include(char *); |
static char *parse_include(char *); |
|
|
#ifdef TRACELEXER |
|
static int sudoers_trace_print(const char *msg); |
|
#else |
|
# define sudoers_trace_print NULL |
|
#endif |
|
int (*trace_print)(const char *msg) = sudoers_trace_print; |
int (*trace_print)(const char *msg) = sudoers_trace_print; |
|
|
#define push_include(_p) (_push_include((_p), FALSE)) | #define LEXRETURN(n) do { \ |
#define push_includedir(_p) (_push_include((_p), TRUE)) | last_token = (n); \ |
| return (n); \ |
| } while (0) |
| |
| #define ECHO ignore_result(fwrite(sudoerstext, sudoersleng, 1, sudoersout)) |
| |
| #define push_include(_p) (_push_include((_p), false)) |
| #define push_includedir(_p) (_push_include((_p), true)) |
%} |
%} |
|
|
HEX16 [0-9A-Fa-f]{1,4} |
HEX16 [0-9A-Fa-f]{1,4} |
Line 109 DEFVAR [a-z_]+
|
Line 128 DEFVAR [a-z_]+
|
%option noinput |
%option noinput |
%option nounput |
%option nounput |
%option noyywrap |
%option noyywrap |
|
%option prefix="sudoers" |
|
|
%s GOTDEFS |
%s GOTDEFS |
%x GOTCMND |
%x GOTCMND |
%x STARTDEFS |
%x STARTDEFS |
%x INDEFS |
%x INDEFS |
%x INSTR |
%x INSTR |
|
%s WANTDIGEST |
|
|
%% |
%% |
<GOTDEFS>[[:blank:]]*,[[:blank:]]* { |
<GOTDEFS>[[:blank:]]*,[[:blank:]]* { |
LEXTRACE(", "); |
LEXTRACE(", "); |
return ','; | LEXRETURN(','); |
} /* return ',' */ |
} /* return ',' */ |
|
|
<GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS; |
<GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS; |
Line 127 DEFVAR [a-z_]+
|
Line 148 DEFVAR [a-z_]+
|
<STARTDEFS>{DEFVAR} { |
<STARTDEFS>{DEFVAR} { |
BEGIN INDEFS; |
BEGIN INDEFS; |
LEXTRACE("DEFVAR "); |
LEXTRACE("DEFVAR "); |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
return DEFVAR; | LEXRETURN(DEFVAR); |
} |
} |
|
|
<INDEFS>{ |
<INDEFS>{ |
, { |
, { |
BEGIN STARTDEFS; |
BEGIN STARTDEFS; |
LEXTRACE(", "); |
LEXTRACE(", "); |
return ','; | LEXRETURN(','); |
} /* return ',' */ |
} /* return ',' */ |
|
|
= { |
= { |
LEXTRACE("= "); |
LEXTRACE("= "); |
return '='; | LEXRETURN('='); |
} /* return '=' */ |
} /* return '=' */ |
|
|
\+= { |
\+= { |
LEXTRACE("+= "); |
LEXTRACE("+= "); |
return '+'; | LEXRETURN('+'); |
} /* return '+' */ |
} /* return '+' */ |
|
|
-= { |
-= { |
LEXTRACE("-= "); |
LEXTRACE("-= "); |
return '-'; | LEXRETURN('-'); |
} /* return '-' */ |
} /* return '-' */ |
|
|
\" { |
\" { |
LEXTRACE("BEGINSTR "); |
LEXTRACE("BEGINSTR "); |
yylval.string = NULL; | sudoerslval.string = NULL; |
prev_state = YY_START; |
prev_state = YY_START; |
BEGIN INSTR; |
BEGIN INSTR; |
} |
} |
|
|
{ENVAR} { |
{ENVAR} { |
LEXTRACE("WORD(2) "); |
LEXTRACE("WORD(2) "); |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
return WORD; | LEXRETURN(WORD); |
} |
} |
} |
} |
|
|
<INSTR>{ |
<INSTR>{ |
\\[[:blank:]]*\n[[:blank:]]* { |
\\[[:blank:]]*\n[[:blank:]]* { |
/* Line continuation char followed by newline. */ |
/* Line continuation char followed by newline. */ |
++sudolineno; | sudolineno++; |
continued = TRUE; | continued = true; |
} |
} |
|
|
\" { |
\" { |
LEXTRACE("ENDSTR "); |
LEXTRACE("ENDSTR "); |
BEGIN prev_state; |
BEGIN prev_state; |
|
|
if (yylval.string == NULL) { | if (sudoerslval.string == NULL) { |
LEXTRACE("ERROR "); /* empty string */ |
LEXTRACE("ERROR "); /* empty string */ |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
if (prev_state == INITIAL) { |
if (prev_state == INITIAL) { |
switch (yylval.string[0]) { | switch (sudoerslval.string[0]) { |
case '%': |
case '%': |
if (yylval.string[1] == '\0' || | if (sudoerslval.string[1] == '\0' || |
(yylval.string[1] == ':' && | (sudoerslval.string[1] == ':' && |
yylval.string[2] == '\0')) { | sudoerslval.string[2] == '\0')) { |
LEXTRACE("ERROR "); /* empty group */ |
LEXTRACE("ERROR "); /* empty group */ |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
LEXTRACE("USERGROUP "); |
LEXTRACE("USERGROUP "); |
return USERGROUP; | LEXRETURN(USERGROUP); |
case '+': |
case '+': |
if (yylval.string[1] == '\0') { | if (sudoerslval.string[1] == '\0') { |
LEXTRACE("ERROR "); /* empty netgroup */ |
LEXTRACE("ERROR "); /* empty netgroup */ |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
LEXTRACE("NETGROUP "); |
LEXTRACE("NETGROUP "); |
return NETGROUP; | LEXRETURN(NETGROUP); |
} |
} |
} |
} |
LEXTRACE("WORD(4) "); |
LEXTRACE("WORD(4) "); |
return WORD; | LEXRETURN(WORD); |
} |
} |
|
|
\\ { |
\\ { |
LEXTRACE("BACKSLASH "); |
LEXTRACE("BACKSLASH "); |
if (!append(yytext, yyleng)) | if (!append(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
} |
} |
|
|
([^\"\n\\]|\\\")+ { |
([^\"\n\\]|\\\")+ { |
LEXTRACE("STRBODY "); |
LEXTRACE("STRBODY "); |
if (!append(yytext, yyleng)) | if (!append(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
} |
} |
} |
} |
Line 225 DEFVAR [a-z_]+
|
Line 246 DEFVAR [a-z_]+
|
\\[\*\?\[\]\!] { |
\\[\*\?\[\]\!] { |
/* quoted fnmatch glob char, pass verbatim */ |
/* quoted fnmatch glob char, pass verbatim */ |
LEXTRACE("QUOTEDCHAR "); |
LEXTRACE("QUOTEDCHAR "); |
if (!fill_args(yytext, 2, sawspace)) | if (!fill_args(sudoerstext, 2, sawspace)) |
yyterminate(); |
yyterminate(); |
sawspace = FALSE; | sawspace = false; |
} |
} |
|
|
\\[:\\,= \t#] { |
\\[:\\,= \t#] { |
/* quoted sudoers special char, strip backslash */ |
/* quoted sudoers special char, strip backslash */ |
LEXTRACE("QUOTEDCHAR "); |
LEXTRACE("QUOTEDCHAR "); |
if (!fill_args(yytext + 1, 1, sawspace)) | if (!fill_args(sudoerstext + 1, 1, sawspace)) |
yyterminate(); |
yyterminate(); |
sawspace = FALSE; | sawspace = false; |
} |
} |
|
|
[#:\,=\n] { |
[#:\,=\n] { |
BEGIN INITIAL; |
BEGIN INITIAL; |
yyless(0); |
yyless(0); |
return COMMAND; | LEXRETURN(COMMAND); |
} /* end of command line args */ |
} /* end of command line args */ |
|
|
[^#\\:, \t\n]+ { |
[^#\\:, \t\n]+ { |
LEXTRACE("ARG "); |
LEXTRACE("ARG "); |
if (!fill_args(yytext, yyleng, sawspace)) | if (!fill_args(sudoerstext, sudoersleng, sawspace)) |
yyterminate(); |
yyterminate(); |
sawspace = FALSE; | sawspace = false; |
} /* a command line arg */ |
} /* a command line arg */ |
} |
} |
|
|
<INITIAL>^#include[[:blank:]]+\/.*\n { | <WANTDIGEST>[[:xdigit:]]+ { |
| /* Only return DIGEST if the length is correct. */ |
| if (sudoersleng == digest_len * 2) { |
| if (!fill(sudoerstext, sudoersleng)) |
| yyterminate(); |
| BEGIN INITIAL; |
| LEXTRACE("DIGEST "); |
| LEXRETURN(DIGEST); |
| } |
| BEGIN INITIAL; |
| yyless(sudoersleng); |
| } /* hex digest */ |
| |
| <WANTDIGEST>[A-Za-z0-9\+/=]+ { |
| /* Only return DIGEST if the length is correct. */ |
| size_t len; |
| if (sudoerstext[sudoersleng - 1] == '=') { |
| /* use padding */ |
| len = 4 * ((digest_len + 2) / 3); |
| } else { |
| /* no padding */ |
| len = (4 * digest_len + 2) / 3; |
| } |
| if (sudoersleng == len) { |
| if (!fill(sudoerstext, sudoersleng)) |
| yyterminate(); |
| BEGIN INITIAL; |
| LEXTRACE("DIGEST "); |
| LEXRETURN(DIGEST); |
| } |
| BEGIN INITIAL; |
| yyless(sudoersleng); |
| } /* base64 digest */ |
| |
| <INITIAL>^#include[[:blank:]]+.*\n { |
char *path; |
char *path; |
|
|
if (continued) { |
if (continued) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
|
|
if ((path = parse_include(yytext)) == NULL) | if ((path = parse_include(sudoerstext)) == NULL) |
yyterminate(); |
yyterminate(); |
|
|
LEXTRACE("INCLUDE\n"); |
LEXTRACE("INCLUDE\n"); |
Line 270 DEFVAR [a-z_]+
|
Line 325 DEFVAR [a-z_]+
|
yyterminate(); |
yyterminate(); |
} |
} |
|
|
<INITIAL>^#includedir[[:blank:]]+\/.*\n { | <INITIAL>^#includedir[[:blank:]]+.*\n { |
char *path; |
char *path; |
|
|
if (continued) { |
if (continued) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
|
|
if ((path = parse_include(yytext)) == NULL) | if ((path = parse_include(sudoerstext)) == NULL) |
yyterminate(); |
yyterminate(); |
|
|
LEXTRACE("INCLUDEDIR\n"); |
LEXTRACE("INCLUDEDIR\n"); |
Line 297 DEFVAR [a-z_]+
|
Line 352 DEFVAR [a-z_]+
|
|
|
if (continued) { |
if (continued) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
|
|
for (n = 0; isblank((unsigned char)yytext[n]); n++) | for (n = 0; isblank((unsigned char)sudoerstext[n]); n++) |
continue; |
continue; |
n += sizeof("Defaults") - 1; |
n += sizeof("Defaults") - 1; |
if ((deftype = yytext[n++]) != '\0') { | if ((deftype = sudoerstext[n++]) != '\0') { |
while (isblank((unsigned char)yytext[n])) | while (isblank((unsigned char)sudoerstext[n])) |
n++; |
n++; |
} |
} |
BEGIN GOTDEFS; |
BEGIN GOTDEFS; |
Line 312 DEFVAR [a-z_]+
|
Line 367 DEFVAR [a-z_]+
|
case ':': |
case ':': |
yyless(n); |
yyless(n); |
LEXTRACE("DEFAULTS_USER "); |
LEXTRACE("DEFAULTS_USER "); |
return DEFAULTS_USER; | LEXRETURN(DEFAULTS_USER); |
case '>': |
case '>': |
yyless(n); |
yyless(n); |
LEXTRACE("DEFAULTS_RUNAS "); |
LEXTRACE("DEFAULTS_RUNAS "); |
return DEFAULTS_RUNAS; | LEXRETURN(DEFAULTS_RUNAS); |
case '@': |
case '@': |
yyless(n); |
yyless(n); |
LEXTRACE("DEFAULTS_HOST "); |
LEXTRACE("DEFAULTS_HOST "); |
return DEFAULTS_HOST; | LEXRETURN(DEFAULTS_HOST); |
case '!': |
case '!': |
yyless(n); |
yyless(n); |
LEXTRACE("DEFAULTS_CMND "); |
LEXTRACE("DEFAULTS_CMND "); |
return DEFAULTS_CMND; | LEXRETURN(DEFAULTS_CMND); |
default: |
default: |
LEXTRACE("DEFAULTS "); |
LEXTRACE("DEFAULTS "); |
return DEFAULTS; | LEXRETURN(DEFAULTS); |
} |
} |
} |
} |
|
|
Line 336 DEFVAR [a-z_]+
|
Line 391 DEFVAR [a-z_]+
|
|
|
if (continued) { |
if (continued) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
|
|
for (n = 0; isblank((unsigned char)yytext[n]); n++) | for (n = 0; isblank((unsigned char)sudoerstext[n]); n++) |
continue; |
continue; |
switch (yytext[n]) { | switch (sudoerstext[n]) { |
case 'H': |
case 'H': |
LEXTRACE("HOSTALIAS "); |
LEXTRACE("HOSTALIAS "); |
return HOSTALIAS; | LEXRETURN(HOSTALIAS); |
case 'C': |
case 'C': |
LEXTRACE("CMNDALIAS "); |
LEXTRACE("CMNDALIAS "); |
return CMNDALIAS; | LEXRETURN(CMNDALIAS); |
case 'U': |
case 'U': |
LEXTRACE("USERALIAS "); |
LEXTRACE("USERALIAS "); |
return USERALIAS; | LEXRETURN(USERALIAS); |
case 'R': |
case 'R': |
LEXTRACE("RUNASALIAS "); |
LEXTRACE("RUNASALIAS "); |
return RUNASALIAS; | LEXRETURN(RUNASALIAS); |
} |
} |
} |
} |
|
|
NOPASSWD[[:blank:]]*: { |
NOPASSWD[[:blank:]]*: { |
/* cmnd does not require passwd for this user */ |
/* cmnd does not require passwd for this user */ |
LEXTRACE("NOPASSWD "); |
LEXTRACE("NOPASSWD "); |
return NOPASSWD; | LEXRETURN(NOPASSWD); |
} |
} |
|
|
PASSWD[[:blank:]]*: { |
PASSWD[[:blank:]]*: { |
/* cmnd requires passwd for this user */ |
/* cmnd requires passwd for this user */ |
LEXTRACE("PASSWD "); |
LEXTRACE("PASSWD "); |
return PASSWD; | LEXRETURN(PASSWD); |
} |
} |
|
|
NOEXEC[[:blank:]]*: { |
NOEXEC[[:blank:]]*: { |
LEXTRACE("NOEXEC "); |
LEXTRACE("NOEXEC "); |
return NOEXEC; | LEXRETURN(NOEXEC); |
} |
} |
|
|
EXEC[[:blank:]]*: { |
EXEC[[:blank:]]*: { |
LEXTRACE("EXEC "); |
LEXTRACE("EXEC "); |
return EXEC; | LEXRETURN(EXEC); |
} |
} |
|
|
SETENV[[:blank:]]*: { |
SETENV[[:blank:]]*: { |
LEXTRACE("SETENV "); |
LEXTRACE("SETENV "); |
return SETENV; | LEXRETURN(SETENV); |
} |
} |
|
|
NOSETENV[[:blank:]]*: { |
NOSETENV[[:blank:]]*: { |
LEXTRACE("NOSETENV "); |
LEXTRACE("NOSETENV "); |
return NOSETENV; | LEXRETURN(NOSETENV); |
} |
} |
|
|
LOG_OUTPUT[[:blank:]]*: { |
LOG_OUTPUT[[:blank:]]*: { |
LEXTRACE("LOG_OUTPUT "); |
LEXTRACE("LOG_OUTPUT "); |
return LOG_OUTPUT; | LEXRETURN(LOG_OUTPUT); |
} |
} |
|
|
NOLOG_OUTPUT[[:blank:]]*: { |
NOLOG_OUTPUT[[:blank:]]*: { |
LEXTRACE("NOLOG_OUTPUT "); |
LEXTRACE("NOLOG_OUTPUT "); |
return NOLOG_OUTPUT; | LEXRETURN(NOLOG_OUTPUT); |
} |
} |
|
|
LOG_INPUT[[:blank:]]*: { |
LOG_INPUT[[:blank:]]*: { |
LEXTRACE("LOG_INPUT "); |
LEXTRACE("LOG_INPUT "); |
return LOG_INPUT; | LEXRETURN(LOG_INPUT); |
} |
} |
|
|
NOLOG_INPUT[[:blank:]]*: { |
NOLOG_INPUT[[:blank:]]*: { |
LEXTRACE("NOLOG_INPUT "); |
LEXTRACE("NOLOG_INPUT "); |
return NOLOG_INPUT; | LEXRETURN(NOLOG_INPUT); |
} |
} |
|
|
<INITIAL,GOTDEFS>(\+|\%|\%:) { |
<INITIAL,GOTDEFS>(\+|\%|\%:) { |
/* empty group or netgroup */ |
/* empty group or netgroup */ |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
|
|
\+{WORD} { |
\+{WORD} { |
/* netgroup */ |
/* netgroup */ |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NETGROUP "); |
LEXTRACE("NETGROUP "); |
return NETGROUP; | LEXRETURN(NETGROUP); |
} |
} |
|
|
\%:?({WORD}|{ID}) { |
\%:?({WORD}|{ID}) { |
/* group */ |
/* group */ |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("USERGROUP "); |
LEXTRACE("USERGROUP "); |
return USERGROUP; | LEXRETURN(USERGROUP); |
} |
} |
|
|
{IPV4ADDR}(\/{IPV4ADDR})? { |
{IPV4ADDR}(\/{IPV4ADDR})? { |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
return NTWKADDR; | LEXRETURN(NTWKADDR); |
} |
} |
|
|
{IPV4ADDR}\/([12]?[0-9]|3[0-2]) { |
{IPV4ADDR}\/([12]?[0-9]|3[0-2]) { |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
return NTWKADDR; | LEXRETURN(NTWKADDR); |
} |
} |
|
|
{IPV6ADDR}(\/{IPV6ADDR})? { |
{IPV6ADDR}(\/{IPV6ADDR})? { |
if (!ipv6_valid(yytext)) { | if (!ipv6_valid(sudoerstext)) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
return NTWKADDR; | LEXRETURN(NTWKADDR); |
} |
} |
|
|
{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) { |
{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) { |
if (!ipv6_valid(yytext)) { | if (!ipv6_valid(sudoerstext)) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
return NTWKADDR; | LEXRETURN(NTWKADDR); |
} |
} |
|
|
ALL { |
ALL { |
LEXTRACE("ALL "); |
LEXTRACE("ALL "); |
return ALL; | LEXRETURN(ALL); |
|
|
} |
} |
|
|
<INITIAL>ROLE { |
<INITIAL>ROLE { |
#ifdef HAVE_SELINUX |
#ifdef HAVE_SELINUX |
LEXTRACE("ROLE "); |
LEXTRACE("ROLE "); |
return ROLE; | LEXRETURN(ROLE); |
#else |
#else |
goto got_alias; |
goto got_alias; |
#endif |
#endif |
Line 485 ALL {
|
Line 540 ALL {
|
<INITIAL>TYPE { |
<INITIAL>TYPE { |
#ifdef HAVE_SELINUX |
#ifdef HAVE_SELINUX |
LEXTRACE("TYPE "); |
LEXTRACE("TYPE "); |
return TYPE; | LEXRETURN(TYPE); |
#else |
#else |
goto got_alias; |
goto got_alias; |
#endif |
#endif |
} |
} |
|
<INITIAL>PRIVS { |
|
#ifdef HAVE_PRIV_SET |
|
LEXTRACE("PRIVS "); |
|
LEXRETURN(PRIVS); |
|
#else |
|
goto got_alias; |
|
#endif |
|
} |
|
|
|
<INITIAL>LIMITPRIVS { |
|
#ifdef HAVE_PRIV_SET |
|
LEXTRACE("LIMITPRIVS "); |
|
LEXRETURN(LIMITPRIVS); |
|
#else |
|
goto got_alias; |
|
#endif |
|
} |
|
|
[[:upper:]][[:upper:][:digit:]_]* { |
[[:upper:]][[:upper:][:digit:]_]* { |
#ifndef HAVE_SELINUX |
|
got_alias: |
got_alias: |
#endif | if (!fill(sudoerstext, sudoersleng)) |
if (!fill(yytext, yyleng)) | |
yyterminate(); |
yyterminate(); |
LEXTRACE("ALIAS "); |
LEXTRACE("ALIAS "); |
return ALIAS; | LEXRETURN(ALIAS); |
} |
} |
|
|
<GOTDEFS>({PATH}|sudoedit) { |
<GOTDEFS>({PATH}|sudoedit) { |
|
/* XXX - no way to specify digest for command */ |
/* no command args allowed for Defaults!/path */ |
/* no command args allowed for Defaults!/path */ |
if (!fill_cmnd(yytext, yyleng)) | if (!fill_cmnd(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("COMMAND "); |
LEXTRACE("COMMAND "); |
return COMMAND; | LEXRETURN(COMMAND); |
} |
} |
|
|
|
sha224 { |
|
digest_len = SHA224_DIGEST_LENGTH; |
|
BEGIN WANTDIGEST; |
|
LEXTRACE("SHA224 "); |
|
LEXRETURN(SHA224); |
|
} |
|
|
|
sha256 { |
|
digest_len = SHA256_DIGEST_LENGTH; |
|
BEGIN WANTDIGEST; |
|
LEXTRACE("SHA256 "); |
|
LEXRETURN(SHA256); |
|
} |
|
|
|
sha384 { |
|
digest_len = SHA384_DIGEST_LENGTH; |
|
BEGIN WANTDIGEST; |
|
LEXTRACE("SHA384 "); |
|
LEXRETURN(SHA384); |
|
} |
|
|
|
sha512 { |
|
digest_len = SHA512_DIGEST_LENGTH; |
|
BEGIN WANTDIGEST; |
|
LEXTRACE("SHA512 "); |
|
LEXRETURN(SHA512); |
|
} |
|
|
sudoedit { |
sudoedit { |
BEGIN GOTCMND; |
BEGIN GOTCMND; |
LEXTRACE("COMMAND "); |
LEXTRACE("COMMAND "); |
if (!fill_cmnd(yytext, yyleng)) | if (!fill_cmnd(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
} /* sudo -e */ |
} /* sudo -e */ |
|
|
{PATH} { |
{PATH} { |
/* directories can't have args... */ |
/* directories can't have args... */ |
if (yytext[yyleng - 1] == '/') { | if (sudoerstext[sudoersleng - 1] == '/') { |
LEXTRACE("COMMAND "); |
LEXTRACE("COMMAND "); |
if (!fill_cmnd(yytext, yyleng)) | if (!fill_cmnd(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
return COMMAND; | LEXRETURN(COMMAND); |
} else { |
} else { |
BEGIN GOTCMND; |
BEGIN GOTCMND; |
LEXTRACE("COMMAND "); |
LEXTRACE("COMMAND "); |
if (!fill_cmnd(yytext, yyleng)) | if (!fill_cmnd(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
} |
} |
} /* a pathname */ |
} /* a pathname */ |
|
|
<INITIAL,GOTDEFS>\" { |
<INITIAL,GOTDEFS>\" { |
LEXTRACE("BEGINSTR "); |
LEXTRACE("BEGINSTR "); |
yylval.string = NULL; | sudoerslval.string = NULL; |
prev_state = YY_START; |
prev_state = YY_START; |
BEGIN INSTR; |
BEGIN INSTR; |
} |
} |
|
|
<INITIAL,GOTDEFS>({ID}|{WORD}) { |
<INITIAL,GOTDEFS>({ID}|{WORD}) { |
/* a word */ |
/* a word */ |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("WORD(5) "); |
LEXTRACE("WORD(5) "); |
return WORD; | LEXRETURN(WORD); |
} |
} |
|
|
\( { |
\( { |
LEXTRACE("( "); |
LEXTRACE("( "); |
return '('; | LEXRETURN('('); |
} |
} |
|
|
\) { |
\) { |
LEXTRACE(") "); |
LEXTRACE(") "); |
return ')'; | LEXRETURN(')'); |
} |
} |
|
|
, { |
, { |
LEXTRACE(", "); |
LEXTRACE(", "); |
return ','; | LEXRETURN(','); |
} /* return ',' */ |
} /* return ',' */ |
|
|
= { |
= { |
LEXTRACE("= "); |
LEXTRACE("= "); |
return '='; | LEXRETURN('='); |
} /* return '=' */ |
} /* return '=' */ |
|
|
: { |
: { |
LEXTRACE(": "); |
LEXTRACE(": "); |
return ':'; | LEXRETURN(':'); |
} /* return ':' */ |
} /* return ':' */ |
|
|
<*>!+ { |
<*>!+ { |
if (yyleng & 1) { | if (sudoersleng & 1) { |
LEXTRACE("!"); |
LEXTRACE("!"); |
return '!'; /* return '!' */ | LEXRETURN('!'); /* return '!' */ |
} |
} |
} |
} |
|
|
<*>\n { |
<*>\n { |
if (YY_START == INSTR) { |
if (YY_START == INSTR) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; /* line break in string */ | LEXRETURN(ERROR); /* line break in string */ |
} |
} |
BEGIN INITIAL; |
BEGIN INITIAL; |
++sudolineno; | sudolineno++; |
continued = FALSE; | continued = false; |
LEXTRACE("\n"); |
LEXTRACE("\n"); |
return COMMENT; | LEXRETURN(COMMENT); |
} /* return newline */ |
} /* return newline */ |
|
|
<*>[[:blank:]]+ { /* throw away space/tabs */ |
<*>[[:blank:]]+ { /* throw away space/tabs */ |
sawspace = TRUE; /* but remember for fill_args */ | sawspace = true; /* but remember for fill_args */ |
} |
} |
|
|
<*>\\[[:blank:]]*\n { |
<*>\\[[:blank:]]*\n { |
sawspace = TRUE; /* remember for fill_args */ | sawspace = true; /* remember for fill_args */ |
++sudolineno; | sudolineno++; |
continued = TRUE; | continued = true; |
} /* throw away EOL after \ */ |
} /* throw away EOL after \ */ |
|
|
<INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n { |
<INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n { |
BEGIN INITIAL; |
BEGIN INITIAL; |
++sudolineno; | sudolineno++; |
continued = FALSE; | continued = false; |
LEXTRACE("#\n"); |
LEXTRACE("#\n"); |
return COMMENT; | LEXRETURN(COMMENT); |
} /* comment, not uid/gid */ |
} /* comment, not uid/gid */ |
|
|
<*>. { |
<*>. { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} /* parse error */ |
} /* parse error */ |
|
|
<*><<EOF>> { |
<*><<EOF>> { |
if (YY_START != INITIAL) { |
if (YY_START != INITIAL) { |
BEGIN INITIAL; |
BEGIN INITIAL; |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
return ERROR; | LEXRETURN(ERROR); |
} |
} |
if (!pop_include()) |
if (!pop_include()) |
yyterminate(); |
yyterminate(); |
Line 634 struct include_stack {
|
Line 733 struct include_stack {
|
char *path; |
char *path; |
struct path_list *more; /* more files in case of includedir */ |
struct path_list *more; /* more files in case of includedir */ |
int lineno; |
int lineno; |
int keepopen; | bool keepopen; |
}; |
}; |
|
|
static int |
static int |
Line 656 switch_dir(struct include_stack *stack, char *dirpath)
|
Line 755 switch_dir(struct include_stack *stack, char *dirpath)
|
struct stat sb; |
struct stat sb; |
struct path_list *pl, *first = NULL; |
struct path_list *pl, *first = NULL; |
struct path_list **sorted = NULL; |
struct path_list **sorted = NULL; |
|
debug_decl(switch_dir, SUDO_DEBUG_PARSER) |
|
|
if (!(dir = opendir(dirpath))) { |
if (!(dir = opendir(dirpath))) { |
if (errno != ENOENT) { |
if (errno != ENOENT) { |
char *errbuf; | warning("%s", dirpath); |
if (asprintf(&errbuf, _("%s: %s"), dirpath, strerror(errno)) != -1) { | sudoerserror(NULL); |
yyerror(errbuf); | |
free(errbuf); | |
} else { | |
yyerror(_("unable to allocate memory")); | |
} | |
} |
} |
goto done; |
goto done; |
} |
} |
Line 690 switch_dir(struct include_stack *stack, char *dirpath)
|
Line 785 switch_dir(struct include_stack *stack, char *dirpath)
|
pl->path = path; |
pl->path = path; |
pl->next = first; |
pl->next = first; |
first = pl; |
first = pl; |
|
path = NULL; |
count++; |
count++; |
} |
} |
closedir(dir); |
closedir(dir); |
Line 726 switch_dir(struct include_stack *stack, char *dirpath)
|
Line 822 switch_dir(struct include_stack *stack, char *dirpath)
|
} |
} |
done: |
done: |
efree(dirpath); |
efree(dirpath); |
return path; | debug_return_str(path); |
bad: |
bad: |
while (first != NULL) { |
while (first != NULL) { |
pl = first; |
pl = first; |
first = pl->next; |
first = pl->next; |
free(pl->path); | efree(pl->path); |
free(pl); | efree(pl); |
} |
} |
efree(sorted); |
efree(sorted); |
efree(dirpath); |
efree(dirpath); |
efree(path); |
efree(path); |
return NULL; | debug_return_str(NULL); |
} |
} |
|
|
#define MAX_SUDOERS_DEPTH 128 |
#define MAX_SUDOERS_DEPTH 128 |
Line 745 bad:
|
Line 841 bad:
|
|
|
static size_t istacksize, idepth; |
static size_t istacksize, idepth; |
static struct include_stack *istack; |
static struct include_stack *istack; |
static int keepopen; | static bool keepopen; |
|
|
void |
void |
init_lexer(void) |
init_lexer(void) |
{ |
{ |
struct path_list *pl; |
struct path_list *pl; |
|
debug_decl(init_lexer, SUDO_DEBUG_PARSER) |
|
|
while (idepth) { |
while (idepth) { |
idepth--; |
idepth--; |
Line 762 init_lexer(void)
|
Line 859 init_lexer(void)
|
efree(istack[idepth].path); |
efree(istack[idepth].path); |
if (idepth && !istack[idepth].keepopen) |
if (idepth && !istack[idepth].keepopen) |
fclose(istack[idepth].bs->yy_input_file); |
fclose(istack[idepth].bs->yy_input_file); |
yy_delete_buffer(istack[idepth].bs); | sudoers_delete_buffer(istack[idepth].bs); |
} |
} |
efree(istack); |
efree(istack); |
istack = NULL; |
istack = NULL; |
istacksize = idepth = 0; |
istacksize = idepth = 0; |
sudolineno = 1; |
sudolineno = 1; |
keepopen = FALSE; | keepopen = false; |
sawspace = FALSE; | sawspace = false; |
continued = FALSE; | continued = false; |
prev_state = INITIAL; |
prev_state = INITIAL; |
|
|
|
debug_return; |
} |
} |
|
|
static int | static bool |
_push_include(char *path, int isdir) | _push_include(char *path, bool isdir) |
{ |
{ |
struct path_list *pl; |
struct path_list *pl; |
FILE *fp; |
FILE *fp; |
|
debug_decl(_push_include, SUDO_DEBUG_PARSER) |
|
|
/* push current state onto stack */ |
/* push current state onto stack */ |
if (idepth >= istacksize) { |
if (idepth >= istacksize) { |
if (idepth > MAX_SUDOERS_DEPTH) { |
if (idepth > MAX_SUDOERS_DEPTH) { |
yyerror(_("too many levels of includes")); | sudoerserror(N_("too many levels of includes")); |
return FALSE; | debug_return_bool(false); |
} |
} |
istacksize += SUDOERS_STACK_INCREMENT; |
istacksize += SUDOERS_STACK_INCREMENT; |
istack = (struct include_stack *) realloc(istack, |
istack = (struct include_stack *) realloc(istack, |
sizeof(*istack) * istacksize); |
sizeof(*istack) * istacksize); |
if (istack == NULL) { |
if (istack == NULL) { |
yyerror(_("unable to allocate memory")); | warning(NULL); |
return FALSE; | sudoerserror(NULL); |
| debug_return_bool(false); |
} |
} |
} |
} |
if (isdir) { |
if (isdir) { |
|
struct stat sb; |
|
switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) { |
|
case SUDO_PATH_SECURE: |
|
break; |
|
case SUDO_PATH_MISSING: |
|
debug_return_bool(false); |
|
case SUDO_PATH_BAD_TYPE: |
|
errno = ENOTDIR; |
|
if (sudoers_warnings) { |
|
warning("%s", path); |
|
} |
|
debug_return_bool(false); |
|
case SUDO_PATH_WRONG_OWNER: |
|
if (sudoers_warnings) { |
|
warningx(_("%s is owned by uid %u, should be %u"), |
|
path, (unsigned int) sb.st_uid, |
|
(unsigned int) sudoers_uid); |
|
} |
|
debug_return_bool(false); |
|
case SUDO_PATH_WORLD_WRITABLE: |
|
if (sudoers_warnings) { |
|
warningx(_("%s is world writable"), path); |
|
} |
|
debug_return_bool(false); |
|
case SUDO_PATH_GROUP_WRITABLE: |
|
if (sudoers_warnings) { |
|
warningx(_("%s is owned by gid %u, should be %u"), |
|
path, (unsigned int) sb.st_gid, |
|
(unsigned int) sudoers_gid); |
|
} |
|
debug_return_bool(false); |
|
default: |
|
/* NOTREACHED */ |
|
debug_return_bool(false); |
|
} |
if (!(path = switch_dir(&istack[idepth], path))) { |
if (!(path = switch_dir(&istack[idepth], path))) { |
/* switch_dir() called yyerror() for us */ | /* switch_dir() called sudoerserror() for us */ |
return FALSE; | debug_return_bool(false); |
} |
} |
while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) { | while ((fp = open_sudoers(path, false, &keepopen)) == NULL) { |
/* Unable to open path in includedir, go to next one, if any. */ |
/* Unable to open path in includedir, go to next one, if any. */ |
efree(path); |
efree(path); |
if ((pl = istack[idepth].more) == NULL) |
if ((pl = istack[idepth].more) == NULL) |
return FALSE; | debug_return_bool(false); |
path = pl->path; |
path = pl->path; |
istack[idepth].more = pl->next; |
istack[idepth].more = pl->next; |
efree(pl); |
efree(pl); |
} |
} |
} else { |
} else { |
if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) { | if ((fp = open_sudoers(path, true, &keepopen)) == NULL) { |
char *errbuf; | /* The error was already printed by open_sudoers() */ |
if (asprintf(&errbuf, _("%s: %s"), path, strerror(errno)) != -1) { | sudoerserror(NULL); |
yyerror(errbuf); | debug_return_bool(false); |
free(errbuf); | |
} else { | |
yyerror(_("unable to allocate memory")); | |
} | |
return FALSE; | |
} |
} |
istack[idepth].more = NULL; |
istack[idepth].more = NULL; |
} |
} |
Line 829 _push_include(char *path, int isdir)
|
Line 960 _push_include(char *path, int isdir)
|
idepth++; |
idepth++; |
sudolineno = 1; |
sudolineno = 1; |
sudoers = path; |
sudoers = path; |
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); | sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE)); |
|
|
return TRUE; | debug_return_bool(true); |
} |
} |
|
|
static int | static bool |
pop_include(void) |
pop_include(void) |
{ |
{ |
struct path_list *pl; |
struct path_list *pl; |
FILE *fp; |
FILE *fp; |
|
debug_decl(pop_include, SUDO_DEBUG_PARSER) |
|
|
if (idepth == 0) |
if (idepth == 0) |
return FALSE; | debug_return_bool(false); |
|
|
if (!keepopen) |
if (!keepopen) |
fclose(YY_CURRENT_BUFFER->yy_input_file); |
fclose(YY_CURRENT_BUFFER->yy_input_file); |
yy_delete_buffer(YY_CURRENT_BUFFER); | sudoers_delete_buffer(YY_CURRENT_BUFFER); |
/* If we are in an include dir, move to the next file. */ |
/* If we are in an include dir, move to the next file. */ |
while ((pl = istack[idepth - 1].more) != NULL) { |
while ((pl = istack[idepth - 1].more) != NULL) { |
fp = open_sudoers(pl->path, FALSE, &keepopen); | fp = open_sudoers(pl->path, false, &keepopen); |
if (fp != NULL) { |
if (fp != NULL) { |
istack[idepth - 1].more = pl->next; |
istack[idepth - 1].more = pl->next; |
efree(sudoers); |
efree(sudoers); |
sudoers = pl->path; |
sudoers = pl->path; |
sudolineno = 1; |
sudolineno = 1; |
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); | sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE)); |
efree(pl); |
efree(pl); |
break; |
break; |
} |
} |
Line 866 pop_include(void)
|
Line 998 pop_include(void)
|
/* If no path list, just pop the last dir on the stack. */ |
/* If no path list, just pop the last dir on the stack. */ |
if (pl == NULL) { |
if (pl == NULL) { |
idepth--; |
idepth--; |
yy_switch_to_buffer(istack[idepth].bs); | sudoers_switch_to_buffer(istack[idepth].bs); |
efree(sudoers); |
efree(sudoers); |
sudoers = istack[idepth].path; |
sudoers = istack[idepth].path; |
sudolineno = istack[idepth].lineno; |
sudolineno = istack[idepth].lineno; |
keepopen = istack[idepth].keepopen; |
keepopen = istack[idepth].keepopen; |
} |
} |
return TRUE; | debug_return_bool(true); |
} |
} |
|
|
static char * |
static char * |
parse_include(char *base) |
parse_include(char *base) |
{ |
{ |
char *cp, *ep, *path; | char *cp, *ep, *path, *pp; |
int len = 0, subst = 0; | int dirlen = 0, len = 0, subst = 0; |
size_t shost_len = 0; |
size_t shost_len = 0; |
|
debug_decl(parse_include, SUDO_DEBUG_PARSER) |
|
|
/* Pull out path from #include line. */ |
/* Pull out path from #include line. */ |
cp = base + sizeof("#include"); |
cp = base + sizeof("#include"); |
Line 898 parse_include(char *base)
|
Line 1031 parse_include(char *base)
|
ep++; |
ep++; |
} |
} |
|
|
/* Make a copy of path and return it. */ | /* Relative paths are located in the same dir as the sudoers file. */ |
| if (*cp != '/') { |
| char *dirend = strrchr(sudoers, '/'); |
| if (dirend != NULL) |
| dirlen = (int)(dirend - sudoers) + 1; |
| } |
| |
| /* Make a copy of the fully-qualified path and return it. */ |
len += (int)(ep - cp); |
len += (int)(ep - cp); |
if ((path = malloc(len + 1)) == NULL) { | path = pp = malloc(len + dirlen + 1); |
yyerror(_("unable to allocate memory")); | if (path == NULL) { |
return NULL; | warning(NULL); |
| sudoerserror(NULL); |
| debug_return_str(NULL); |
} |
} |
|
if (dirlen) { |
|
memcpy(path, sudoers, dirlen); |
|
pp += dirlen; |
|
} |
if (subst) { |
if (subst) { |
/* substitute for %h */ |
/* substitute for %h */ |
char *pp = path; |
|
while (cp < ep) { |
while (cp < ep) { |
if (cp[0] == '%' && cp[1] == 'h') { |
if (cp[0] == '%' && cp[1] == 'h') { |
memcpy(pp, user_shost, shost_len); |
memcpy(pp, user_shost, shost_len); |
Line 918 parse_include(char *base)
|
Line 1063 parse_include(char *base)
|
} |
} |
*pp = '\0'; |
*pp = '\0'; |
} else { |
} else { |
memcpy(path, cp, len); | memcpy(pp, cp, len); |
path[len] = '\0'; | pp[len] = '\0'; |
} |
} |
|
|
/* Push any excess characters (e.g. comment, newline) back to the lexer */ |
/* Push any excess characters (e.g. comment, newline) back to the lexer */ |
if (*ep != '\0') |
if (*ep != '\0') |
yyless((int)(ep - base)); |
yyless((int)(ep - base)); |
|
|
return path; | debug_return_str(path); |
} |
} |
|
|
#ifdef TRACELEXER |
#ifdef TRACELEXER |
static int | int |
sudoers_trace_print(const char *msg) |
sudoers_trace_print(const char *msg) |
{ |
{ |
return fputs(msg, stderr); |
return fputs(msg, stderr); |
|
} |
|
#else |
|
int |
|
sudoers_trace_print(const char *msg) |
|
{ |
|
static bool initialized; |
|
static struct lbuf lbuf; |
|
|
|
if (!initialized) { |
|
initialized = true; |
|
lbuf_init(&lbuf, NULL, 0, NULL, 0); |
|
} |
|
|
|
lbuf_append(&lbuf, "%s", msg); |
|
/* XXX - assumes a final newline */ |
|
if (strchr(msg, '\n') != NULL) |
|
{ |
|
sudo_debug_printf2(NULL, NULL, 0, SUDO_DEBUG_PARSER|SUDO_DEBUG_DEBUG, |
|
"%s:%d %s", sudoers, sudolineno, lbuf.buf); |
|
lbuf.len = 0; |
|
} |
|
return 0; |
} |
} |
#endif /* TRACELEXER */ |
#endif /* TRACELEXER */ |