version 1.1.1.3, 2012/10/09 09:29:52
|
version 1.1.1.5, 2014/06/15 16:12:54
|
Line 1
|
Line 1
|
%{ |
%{ |
/* |
/* |
* Copyright (c) 1996, 1998-2005, 2007-2012 | * 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 72
|
Line 76
|
#include "toke.h" |
#include "toke.h" |
#include <gram.h> |
#include <gram.h> |
#include "lbuf.h" |
#include "lbuf.h" |
|
#include "sha2.h" |
#include "secure_path.h" |
#include "secure_path.h" |
|
|
extern YYSTYPE yylval; | int sudolineno; /* current sudoers line number. */ |
extern bool parse_error; | int last_token; /* last token that was parsed. */ |
extern bool sudoers_warnings; | char *sudoers; /* sudoers file being parsed. */ |
int sudolineno; | |
int last_token; | |
char *sudoers; | |
|
|
/* Default sudoers path, mode and owner (may be set via sudo.conf) */ |
/* Default sudoers path, mode and owner (may be set via sudo.conf) */ |
const char *sudoers_file = _PATH_SUDOERS; |
const char *sudoers_file = _PATH_SUDOERS; |
Line 89 gid_t sudoers_gid = SUDOERS_GID;
|
Line 91 gid_t sudoers_gid = SUDOERS_GID;
|
|
|
static bool continued, sawspace; |
static bool continued, sawspace; |
static int prev_state; |
static int prev_state; |
|
static int digest_len; |
|
|
static bool _push_include(char *, bool); |
static bool _push_include(char *, bool); |
static bool pop_include(void); |
static bool pop_include(void); |
Line 101 int (*trace_print)(const char *msg) = sudoers_trace_pr
|
Line 104 int (*trace_print)(const char *msg) = sudoers_trace_pr
|
return (n); \ |
return (n); \ |
} while (0) |
} while (0) |
|
|
#define ECHO ignore_result(fwrite(yytext, yyleng, 1, yyout)) | #define ECHO ignore_result(fwrite(sudoerstext, sudoersleng, 1, sudoersout)) |
|
|
#define push_include(_p) (_push_include((_p), false)) |
#define push_include(_p) (_push_include((_p), false)) |
#define push_includedir(_p) (_push_include((_p), true)) |
#define push_includedir(_p) (_push_include((_p), true)) |
Line 122 DEFVAR [a-z_]+
|
Line 125 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:]]* { |
Line 140 DEFVAR [a-z_]+
|
Line 145 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(); |
LEXRETURN(DEFVAR); |
LEXRETURN(DEFVAR); |
} |
} |
Line 169 DEFVAR [a-z_]+
|
Line 174 DEFVAR [a-z_]+
|
|
|
\" { |
\" { |
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(); |
LEXRETURN(WORD); |
LEXRETURN(WORD); |
} |
} |
Line 193 DEFVAR [a-z_]+
|
Line 198 DEFVAR [a-z_]+
|
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 */ |
LEXRETURN(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 */ |
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
LEXTRACE("USERGROUP "); |
LEXTRACE("USERGROUP "); |
LEXRETURN(USERGROUP); |
LEXRETURN(USERGROUP); |
case '+': |
case '+': |
if (yylval.string[1] == '\0') { | if (sudoerslval.string[1] == '\0') { |
LEXTRACE("ERROR "); /* empty netgroup */ |
LEXTRACE("ERROR "); /* empty netgroup */ |
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
Line 223 DEFVAR [a-z_]+
|
Line 228 DEFVAR [a-z_]+
|
|
|
\\ { |
\\ { |
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 238 DEFVAR [a-z_]+
|
Line 243 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; |
} |
} |
Line 246 DEFVAR [a-z_]+
|
Line 251 DEFVAR [a-z_]+
|
\\[:\\,= \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; |
} |
} |
Line 259 DEFVAR [a-z_]+
|
Line 264 DEFVAR [a-z_]+
|
|
|
[^#\\:, \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 */ |
} |
} |
|
|
|
<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. */ |
|
int 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 { |
<INITIAL>^#include[[:blank:]]+.*\n { |
char *path; |
char *path; |
|
|
Line 273 DEFVAR [a-z_]+
|
Line 312 DEFVAR [a-z_]+
|
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
|
|
if ((path = parse_include(yytext)) == NULL) | if ((path = parse_include(sudoerstext)) == NULL) |
yyterminate(); |
yyterminate(); |
|
|
LEXTRACE("INCLUDE\n"); |
LEXTRACE("INCLUDE\n"); |
Line 291 DEFVAR [a-z_]+
|
Line 330 DEFVAR [a-z_]+
|
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
|
|
if ((path = parse_include(yytext)) == NULL) | if ((path = parse_include(sudoerstext)) == NULL) |
yyterminate(); |
yyterminate(); |
|
|
LEXTRACE("INCLUDEDIR\n"); |
LEXTRACE("INCLUDEDIR\n"); |
Line 313 DEFVAR [a-z_]+
|
Line 352 DEFVAR [a-z_]+
|
LEXRETURN(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 352 DEFVAR [a-z_]+
|
Line 391 DEFVAR [a-z_]+
|
LEXRETURN(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 "); |
LEXRETURN(HOSTALIAS); |
LEXRETURN(HOSTALIAS); |
Line 430 NOLOG_INPUT[[:blank:]]*: {
|
Line 469 NOLOG_INPUT[[:blank:]]*: {
|
|
|
\+{WORD} { |
\+{WORD} { |
/* netgroup */ |
/* netgroup */ |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NETGROUP "); |
LEXTRACE("NETGROUP "); |
LEXRETURN(NETGROUP); |
LEXRETURN(NETGROUP); |
Line 438 NOLOG_INPUT[[:blank:]]*: {
|
Line 477 NOLOG_INPUT[[:blank:]]*: {
|
|
|
\%:?({WORD}|{ID}) { |
\%:?({WORD}|{ID}) { |
/* group */ |
/* group */ |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("USERGROUP "); |
LEXTRACE("USERGROUP "); |
LEXRETURN(USERGROUP); |
LEXRETURN(USERGROUP); |
} |
} |
|
|
{IPV4ADDR}(\/{IPV4ADDR})? { |
{IPV4ADDR}(\/{IPV4ADDR})? { |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
LEXRETURN(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 "); |
LEXRETURN(NTWKADDR); |
LEXRETURN(NTWKADDR); |
} |
} |
|
|
{IPV6ADDR}(\/{IPV6ADDR})? { |
{IPV6ADDR}(\/{IPV6ADDR})? { |
if (!ipv6_valid(yytext)) { | if (!ipv6_valid(sudoerstext)) { |
LEXTRACE("ERROR "); |
LEXTRACE("ERROR "); |
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
LEXRETURN(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 "); |
LEXRETURN(ERROR); |
LEXRETURN(ERROR); |
} |
} |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("NTWKADDR "); |
LEXTRACE("NTWKADDR "); |
LEXRETURN(NTWKADDR); |
LEXRETURN(NTWKADDR); |
Line 523 ALL {
|
Line 562 ALL {
|
|
|
[[:upper:]][[:upper:][:digit:]_]* { |
[[:upper:]][[:upper:][:digit:]_]* { |
got_alias: |
got_alias: |
if (!fill(yytext, yyleng)) | if (!fill(sudoerstext, sudoersleng)) |
yyterminate(); |
yyterminate(); |
LEXTRACE("ALIAS "); |
LEXTRACE("ALIAS "); |
LEXRETURN(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 "); |
LEXRETURN(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(); |
LEXRETURN(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) "); |
LEXRETURN(WORD); |
LEXRETURN(WORD); |
Line 600 sudoedit {
|
Line 668 sudoedit {
|
} /* return ':' */ |
} /* return ':' */ |
|
|
<*>!+ { |
<*>!+ { |
if (yyleng & 1) { | if (sudoersleng & 1) { |
LEXTRACE("!"); |
LEXTRACE("!"); |
LEXRETURN('!'); /* return '!' */ |
LEXRETURN('!'); /* return '!' */ |
} |
} |
Line 628 sudoedit {
|
Line 696 sudoedit {
|
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; | if (sudoerstext[sudoersleng - 1] == '\n') { |
sudolineno++; | /* comment ending in a newline */ |
continued = false; | BEGIN INITIAL; |
| sudolineno++; |
| continued = false; |
| } else if (!feof(yyin)) { |
| LEXTRACE("ERROR "); |
| LEXRETURN(ERROR); |
| } |
LEXTRACE("#\n"); |
LEXTRACE("#\n"); |
LEXRETURN(COMMENT); |
LEXRETURN(COMMENT); |
} /* comment, not uid/gid */ |
} /* comment, not uid/gid */ |
Line 653 sudoedit {
|
Line 727 sudoedit {
|
|
|
%% |
%% |
struct path_list { |
struct path_list { |
|
SLIST_ENTRY(path_list) entries; |
char *path; |
char *path; |
struct path_list *next; |
|
}; |
}; |
|
|
|
SLIST_HEAD(path_list_head, path_list); |
|
|
struct include_stack { |
struct include_stack { |
YY_BUFFER_STATE bs; |
YY_BUFFER_STATE bs; |
char *path; |
char *path; |
struct path_list *more; /* more files in case of includedir */ | struct path_list_head more; /* more files in case of includedir */ |
int lineno; |
int lineno; |
bool keepopen; |
bool keepopen; |
}; |
}; |
|
|
|
/* |
|
* Compare two struct path_list structs in reverse order. |
|
*/ |
static int |
static int |
pl_compare(const void *v1, const void *v2) |
pl_compare(const void *v1, const void *v2) |
{ |
{ |
const struct path_list * const *p1 = v1; |
const struct path_list * const *p1 = v1; |
const struct path_list * const *p2 = v2; |
const struct path_list * const *p2 = v2; |
|
|
return strcmp((*p1)->path, (*p2)->path); | return strcmp((*p2)->path, (*p1)->path); |
} |
} |
|
|
static char * |
static char * |
switch_dir(struct include_stack *stack, char *dirpath) |
switch_dir(struct include_stack *stack, char *dirpath) |
{ |
{ |
DIR *dir; |
DIR *dir; |
int i, count = 0; | unsigned int i, count = 0; |
| unsigned int max_paths = 32; |
char *path = NULL; |
char *path = NULL; |
struct dirent *dent; |
struct dirent *dent; |
struct stat sb; |
struct stat sb; |
struct path_list *pl, *first = NULL; | struct path_list *pl, **paths = NULL; |
struct path_list **sorted = NULL; | |
debug_decl(switch_dir, SUDO_DEBUG_PARSER) |
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; |
} |
} |
|
paths = malloc(sizeof(*paths) * max_paths); |
|
if (paths == NULL) { |
|
closedir(dir); |
|
goto bad; |
|
} |
while ((dent = readdir(dir))) { |
while ((dent = readdir(dir))) { |
/* Ignore files that end in '~' or have a '.' in them. */ |
/* Ignore files that end in '~' or have a '.' in them. */ |
if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' |
if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' |
Line 717 switch_dir(struct include_stack *stack, char *dirpath)
|
Line 796 switch_dir(struct include_stack *stack, char *dirpath)
|
if (pl == NULL) |
if (pl == NULL) |
goto bad; |
goto bad; |
pl->path = path; |
pl->path = path; |
pl->next = first; | if (count >= max_paths) { |
first = pl; | struct path_list **tmp; |
count++; | max_paths <<= 1; |
| tmp = realloc(paths, sizeof(*paths) * max_paths); |
| if (tmp == NULL) { |
| closedir(dir); |
| goto bad; |
| } |
| paths = tmp; |
| } |
| paths[count++] = pl; |
| path = NULL; |
} |
} |
closedir(dir); |
closedir(dir); |
|
|
if (count == 0) |
if (count == 0) |
goto done; |
goto done; |
|
|
/* Sort the list as an array. */ | /* Sort the list as an array in reverse order. */ |
sorted = malloc(sizeof(*sorted) * count); | qsort(paths, count, sizeof(*paths), pl_compare); |
if (sorted == NULL) | |
goto bad; | /* Build up the list in sorted order. */ |
pl = first; | |
for (i = 0; i < count; i++) { |
for (i = 0; i < count; i++) { |
sorted[i] = pl; | SLIST_INSERT_HEAD(&stack->more, paths[i], entries); |
pl = pl->next; | |
} |
} |
qsort(sorted, count, sizeof(*sorted), pl_compare); |
|
|
|
/* Apply sorting to the list. */ |
|
first = sorted[0]; |
|
sorted[count - 1]->next = NULL; |
|
for (i = 1; i < count; i++) |
|
sorted[i - 1]->next = sorted[i]; |
|
efree(sorted); |
|
|
|
/* Pull out the first element for parsing, leave the rest for later. */ |
/* Pull out the first element for parsing, leave the rest for later. */ |
if (count) { | pl = SLIST_FIRST(&stack->more); |
path = first->path; | SLIST_REMOVE_HEAD(&stack->more, entries); |
pl = first->next; | path = pl->path; |
efree(first); | efree(pl); |
stack->more = pl; | |
} else { | |
path = NULL; | |
} | |
done: |
done: |
|
efree(paths); |
efree(dirpath); |
efree(dirpath); |
debug_return_str(path); |
debug_return_str(path); |
bad: |
bad: |
while (first != NULL) { | for (i = 0; i < count; i++) { |
pl = first; | efree(paths[i]->path); |
first = pl->next; | efree(paths[i]); |
free(pl->path); | |
free(pl); | |
} |
} |
efree(sorted); | efree(paths); |
efree(dirpath); |
efree(dirpath); |
efree(path); |
efree(path); |
debug_return_str(NULL); |
debug_return_str(NULL); |
Line 784 init_lexer(void)
|
Line 857 init_lexer(void)
|
|
|
while (idepth) { |
while (idepth) { |
idepth--; |
idepth--; |
while ((pl = istack[idepth].more) != NULL) { | while ((pl = SLIST_FIRST(&istack[idepth].more)) != NULL) { |
istack[idepth].more = pl->next; | SLIST_REMOVE_HEAD(&istack[idepth].more, entries); |
efree(pl->path); |
efree(pl->path); |
efree(pl); |
efree(pl); |
} |
} |
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; |
Line 815 _push_include(char *path, bool isdir)
|
Line 888 _push_include(char *path, bool isdir)
|
|
|
/* push current state onto stack */ |
/* push current state onto stack */ |
if (idepth >= istacksize) { |
if (idepth >= istacksize) { |
|
struct include_stack *new_istack; |
|
|
if (idepth > MAX_SUDOERS_DEPTH) { |
if (idepth > MAX_SUDOERS_DEPTH) { |
yyerror(_("too many levels of includes")); | sudoerserror(N_("too many levels of includes")); |
debug_return_bool(false); |
debug_return_bool(false); |
} |
} |
istacksize += SUDOERS_STACK_INCREMENT; |
istacksize += SUDOERS_STACK_INCREMENT; |
istack = (struct include_stack *) realloc(istack, | new_istack = (struct include_stack *) realloc(istack, |
sizeof(*istack) * istacksize); |
sizeof(*istack) * istacksize); |
if (istack == NULL) { | if (new_istack == NULL) { |
yyerror(_("unable to allocate memory")); | warning(NULL); |
| sudoerserror(NULL); |
debug_return_bool(false); |
debug_return_bool(false); |
} |
} |
|
istack = new_istack; |
} |
} |
|
SLIST_INIT(&istack[idepth].more); |
if (isdir) { |
if (isdir) { |
struct stat sb; |
struct stat sb; |
switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) { |
switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) { |
Line 842 _push_include(char *path, bool isdir)
|
Line 920 _push_include(char *path, bool isdir)
|
debug_return_bool(false); |
debug_return_bool(false); |
case SUDO_PATH_WRONG_OWNER: |
case SUDO_PATH_WRONG_OWNER: |
if (sudoers_warnings) { |
if (sudoers_warnings) { |
warningx(_("%s is owned by uid %u, should be %u"), | warningx(U_("%s is owned by uid %u, should be %u"), |
path, (unsigned int) sb.st_uid, |
path, (unsigned int) sb.st_uid, |
(unsigned int) sudoers_uid); |
(unsigned int) sudoers_uid); |
} |
} |
debug_return_bool(false); |
debug_return_bool(false); |
case SUDO_PATH_WORLD_WRITABLE: |
case SUDO_PATH_WORLD_WRITABLE: |
if (sudoers_warnings) { |
if (sudoers_warnings) { |
warningx(_("%s is world writable"), path); | warningx(U_("%s is world writable"), path); |
} |
} |
debug_return_bool(false); |
debug_return_bool(false); |
case SUDO_PATH_GROUP_WRITABLE: |
case SUDO_PATH_GROUP_WRITABLE: |
if (sudoers_warnings) { |
if (sudoers_warnings) { |
warningx(_("%s is owned by gid %u, should be %u"), | warningx(U_("%s is owned by gid %u, should be %u"), |
path, (unsigned int) sb.st_gid, |
path, (unsigned int) sb.st_gid, |
(unsigned int) sudoers_gid); |
(unsigned int) sudoers_gid); |
} |
} |
Line 864 _push_include(char *path, bool isdir)
|
Line 942 _push_include(char *path, bool isdir)
|
debug_return_bool(false); |
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 */ |
debug_return_bool(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 = SLIST_FIRST(&istack[idepth].more)) == NULL) |
debug_return_bool(false); |
debug_return_bool(false); |
|
SLIST_REMOVE_HEAD(&istack[idepth].more, entries); |
path = pl->path; |
path = pl->path; |
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) { |
/* The error was already printed by open_sudoers() */ |
/* The error was already printed by open_sudoers() */ |
yyerror(NULL); | sudoerserror(NULL); |
debug_return_bool(false); |
debug_return_bool(false); |
} |
} |
istack[idepth].more = NULL; |
|
} |
} |
/* Push the old (current) file and open the new one. */ |
/* Push the old (current) file and open the new one. */ |
istack[idepth].path = sudoers; /* push old path */ |
istack[idepth].path = sudoers; /* push old path */ |
Line 892 _push_include(char *path, bool isdir)
|
Line 969 _push_include(char *path, bool 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)); |
|
|
debug_return_bool(true); |
debug_return_bool(true); |
} |
} |
Line 909 pop_include(void)
|
Line 986 pop_include(void)
|
|
|
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 = SLIST_FIRST(&istack[idepth - 1].more)) != NULL) { |
| SLIST_REMOVE_HEAD(&istack[idepth - 1].more, entries); |
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; |
|
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; |
} |
} |
/* Unable to open path in include dir, go to next one. */ |
/* Unable to open path in include dir, go to next one. */ |
istack[idepth - 1].more = pl->next; |
|
efree(pl->path); |
efree(pl->path); |
efree(pl); |
efree(pl); |
} |
} |
/* 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; |
Line 974 parse_include(char *base)
|
Line 1050 parse_include(char *base)
|
len += (int)(ep - cp); |
len += (int)(ep - cp); |
path = pp = malloc(len + dirlen + 1); |
path = pp = malloc(len + dirlen + 1); |
if (path == NULL) { |
if (path == NULL) { |
yyerror(_("unable to allocate memory")); | warning(NULL); |
| sudoerserror(NULL); |
debug_return_str(NULL); |
debug_return_str(NULL); |
} |
} |
if (dirlen) { |
if (dirlen) { |