version 1.1.1.4, 2013/07/22 10:46:12
|
version 1.1.1.5, 2014/06/15 16:12:54
|
Line 79
|
Line 79
|
#include "sha2.h" |
#include "sha2.h" |
#include "secure_path.h" |
#include "secure_path.h" |
|
|
extern YYSTYPE sudoerslval; | 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 288 DEFVAR [a-z_]+
|
Line 285 DEFVAR [a-z_]+
|
|
|
<WANTDIGEST>[A-Za-z0-9\+/=]+ { |
<WANTDIGEST>[A-Za-z0-9\+/=]+ { |
/* Only return DIGEST if the length is correct. */ |
/* Only return DIGEST if the length is correct. */ |
size_t len; | int len; |
if (sudoerstext[sudoersleng - 1] == '=') { |
if (sudoerstext[sudoersleng - 1] == '=') { |
/* use padding */ |
/* use padding */ |
len = 4 * ((digest_len + 2) / 3); |
len = 4 * ((digest_len + 2) / 3); |
Line 699 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 724 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))) { |
Line 764 switch_dir(struct include_stack *stack, char *dirpath)
|
Line 772 switch_dir(struct include_stack *stack, char *dirpath)
|
} |
} |
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 783 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; |
| max_paths <<= 1; |
| tmp = realloc(paths, sizeof(*paths) * max_paths); |
| if (tmp == NULL) { |
| closedir(dir); |
| goto bad; |
| } |
| paths = tmp; |
| } |
| paths[count++] = pl; |
path = NULL; |
path = NULL; |
count++; |
|
} |
} |
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]); |
efree(pl->path); | |
efree(pl); | |
} |
} |
efree(sorted); | efree(paths); |
efree(dirpath); |
efree(dirpath); |
efree(path); |
efree(path); |
debug_return_str(NULL); |
debug_return_str(NULL); |
Line 851 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); |
} |
} |
Line 882 _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) { |
sudoerserror(N_("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) { |
warning(NULL); |
warning(NULL); |
sudoerserror(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 910 _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 938 _push_include(char *path, bool isdir)
|
Line 948 _push_include(char *path, bool isdir)
|
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 { |
Line 950 _push_include(char *path, bool isdir)
|
Line 960 _push_include(char *path, bool isdir)
|
sudoerserror(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 979 pop_include(void)
|
Line 988 pop_include(void)
|
fclose(YY_CURRENT_BUFFER->yy_input_file); |
fclose(YY_CURRENT_BUFFER->yy_input_file); |
sudoers_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; |
Line 991 pop_include(void)
|
Line 1000 pop_include(void)
|
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); |
} |
} |