|
version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.3, 2012/10/09 09:29:52
|
|
Line 1
|
Line 1
|
| %{ |
%{ |
| /* |
/* |
| * Copyright (c) 1996, 1998-2005, 2007-2011 | * Copyright (c) 1996, 1998-2005, 2007-2012 |
| * 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 44
|
Line 44
|
| #ifdef HAVE_UNISTD_H |
#ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
# include <unistd.h> |
| #endif /* HAVE_UNISTD_H */ |
#endif /* HAVE_UNISTD_H */ |
| |
#ifdef HAVE_INTTYPES_H |
| |
# include <inttypes.h> |
| |
#endif |
| #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) |
#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) |
| # include <alloca.h> |
# include <alloca.h> |
| #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ |
#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ |
|
Line 52
|
Line 55
|
| #include "sudoers.h" /* XXX */ |
#include "sudoers.h" /* XXX */ |
| #include "parse.h" |
#include "parse.h" |
| #include "toke.h" |
#include "toke.h" |
| |
#include "gram.h" |
| |
|
| /* |
/* |
| * We must define SIZE_MAX for yacc's skeleton.c. |
* We must define SIZE_MAX for yacc's skeleton.c. |
|
Line 70
|
Line 74
|
| * Globals |
* Globals |
| */ |
*/ |
| extern int sudolineno; |
extern int sudolineno; |
| |
extern int last_token; |
| extern char *sudoers; |
extern char *sudoers; |
| static int verbose = FALSE; | bool sudoers_warnings = true; |
| int parse_error = FALSE; | bool parse_error = false; |
| int pedantic = FALSE; | |
| int errorlineno = -1; |
int errorlineno = -1; |
| char *errorfile = NULL; |
char *errorfile = NULL; |
| |
|
|
Line 92 static struct member *new_member(char *, int);
|
Line 96 static struct member *new_member(char *, int);
|
| void |
void |
| yyerror(const char *s) |
yyerror(const char *s) |
| { |
{ |
| |
debug_decl(yyerror, SUDO_DEBUG_PARSER) |
| |
|
| |
/* If we last saw a newline the error is on the preceding line. */ |
| |
if (last_token == COMMENT) |
| |
sudolineno--; |
| |
|
| /* Save the line the first error occurred on. */ |
/* Save the line the first error occurred on. */ |
| if (errorlineno == -1) { |
if (errorlineno == -1) { |
| errorlineno = sudolineno ? sudolineno - 1 : 0; | errorlineno = sudolineno; |
| errorfile = estrdup(sudoers); |
errorfile = estrdup(sudoers); |
| } |
} |
| if (trace_print != NULL) { | if (sudoers_warnings && s != NULL) { |
| LEXTRACE("<*> "); |
LEXTRACE("<*> "); |
| } else if (verbose && s != NULL) { | #ifndef TRACELEXER |
| warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, | if (trace_print == NULL || trace_print == sudoers_trace_print) |
| sudolineno ? sudolineno - 1 : 0); | warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno); |
| | #endif |
| } |
} |
| parse_error = TRUE; | parse_error = true; |
| | debug_return; |
| } |
} |
| %} |
%} |
| |
|
|
Line 116 yyerror(const char *s)
|
Line 128 yyerror(const char *s)
|
| struct sudo_command command; |
struct sudo_command command; |
| struct cmndtag tag; |
struct cmndtag tag; |
| struct selinux_info seinfo; |
struct selinux_info seinfo; |
| |
struct solaris_privs_info privinfo; |
| char *string; |
char *string; |
| int tok; |
int tok; |
| } |
} |
|
Line 154 yyerror(const char *s)
|
Line 167 yyerror(const char *s)
|
| %token <tok> ERROR |
%token <tok> ERROR |
| %token <tok> TYPE /* SELinux type */ |
%token <tok> TYPE /* SELinux type */ |
| %token <tok> ROLE /* SELinux role */ |
%token <tok> ROLE /* SELinux role */ |
| |
%token <tok> PRIVS /* Solaris privileges */ |
| |
%token <tok> LIMITPRIVS /* Solaris limit privileges */ |
| |
%token <tok> MYSELF /* run as myself, not another user */ |
| |
|
| %type <cmndspec> cmndspec |
%type <cmndspec> cmndspec |
| %type <cmndspec> cmndspeclist |
%type <cmndspec> cmndspeclist |
|
Line 179 yyerror(const char *s)
|
Line 195 yyerror(const char *s)
|
| %type <seinfo> selinux |
%type <seinfo> selinux |
| %type <string> rolespec |
%type <string> rolespec |
| %type <string> typespec |
%type <string> typespec |
| |
%type <privinfo> solarisprivs |
| |
%type <string> privsspec |
| |
%type <string> limitprivsspec |
| |
|
| %% |
%% |
| |
|
|
Line 236 defaults_list : defaults_entry
|
Line 255 defaults_list : defaults_entry
|
| ; |
; |
| |
|
| defaults_entry : DEFVAR { |
defaults_entry : DEFVAR { |
| $$ = new_default($1, NULL, TRUE); | $$ = new_default($1, NULL, true); |
| } |
} |
| | '!' DEFVAR { |
| '!' DEFVAR { |
| $$ = new_default($2, NULL, FALSE); | $$ = new_default($2, NULL, false); |
| } |
} |
| | DEFVAR '=' WORD { |
| DEFVAR '=' WORD { |
| $$ = new_default($1, $3, TRUE); | $$ = new_default($1, $3, true); |
| } |
} |
| | DEFVAR '+' WORD { |
| DEFVAR '+' WORD { |
| $$ = new_default($1, $3, '+'); |
$$ = new_default($1, $3, '+'); |
|
Line 260 privileges : privilege
|
Line 279 privileges : privilege
|
| ; |
; |
| |
|
| privilege : hostlist '=' cmndspeclist { |
privilege : hostlist '=' cmndspeclist { |
| struct privilege *p = emalloc(sizeof(*p)); | struct privilege *p = ecalloc(1, sizeof(*p)); |
| list2tq(&p->hostlist, $1); |
list2tq(&p->hostlist, $1); |
| list2tq(&p->cmndlist, $3); |
list2tq(&p->cmndlist, $3); |
| p->prev = p; |
p->prev = p; |
| p->next = NULL; | /* p->next = NULL; */ |
| $$ = p; |
$$ = p; |
| } |
} |
| ; |
; |
| |
|
| ophost : host { |
ophost : host { |
| $$ = $1; |
$$ = $1; |
| $$->negated = FALSE; | $$->negated = false; |
| } |
} |
| | '!' host { |
| '!' host { |
| $$ = $2; |
$$ = $2; |
| $$->negated = TRUE; | $$->negated = true; |
| } |
} |
| ; |
; |
| |
|
|
Line 306 cmndspeclist : cmndspec
|
Line 325 cmndspeclist : cmndspec
|
| if ($3->type == NULL) |
if ($3->type == NULL) |
| $3->type = $3->prev->type; |
$3->type = $3->prev->type; |
| #endif /* HAVE_SELINUX */ |
#endif /* HAVE_SELINUX */ |
| |
#ifdef HAVE_PRIV_SET |
| |
/* propagate privs & limitprivs */ |
| |
if ($3->privs == NULL) |
| |
$3->privs = $3->prev->privs; |
| |
if ($3->limitprivs == NULL) |
| |
$3->limitprivs = $3->prev->limitprivs; |
| |
#endif /* HAVE_PRIV_SET */ |
| /* propagate tags and runas list */ |
/* propagate tags and runas list */ |
| if ($3->tags.nopasswd == UNSPEC) |
if ($3->tags.nopasswd == UNSPEC) |
| $3->tags.nopasswd = $3->prev->tags.nopasswd; |
$3->tags.nopasswd = $3->prev->tags.nopasswd; |
|
Line 329 cmndspeclist : cmndspec
|
Line 355 cmndspeclist : cmndspec
|
| } |
} |
| ; |
; |
| |
|
| cmndspec : runasspec selinux cmndtag opcmnd { | cmndspec : runasspec selinux solarisprivs cmndtag opcmnd { |
| struct cmndspec *cs = emalloc(sizeof(*cs)); | struct cmndspec *cs = ecalloc(1, sizeof(*cs)); |
| if ($1 != NULL) { |
if ($1 != NULL) { |
| list2tq(&cs->runasuserlist, $1->runasusers); |
list2tq(&cs->runasuserlist, $1->runasusers); |
| list2tq(&cs->runasgrouplist, $1->runasgroups); |
list2tq(&cs->runasgrouplist, $1->runasgroups); |
|
Line 343 cmndspec : runasspec selinux cmndtag opcmnd {
|
Line 369 cmndspec : runasspec selinux cmndtag opcmnd {
|
| cs->role = $2.role; |
cs->role = $2.role; |
| cs->type = $2.type; |
cs->type = $2.type; |
| #endif |
#endif |
| cs->tags = $3; | #ifdef HAVE_PRIV_SET |
| cs->cmnd = $4; | cs->privs = $3.privs; |
| | cs->limitprivs = $3.limitprivs; |
| | #endif |
| | cs->tags = $4; |
| | cs->cmnd = $5; |
| cs->prev = cs; |
cs->prev = cs; |
| cs->next = NULL; |
cs->next = NULL; |
| /* sudo "ALL" implies the SETENV tag */ |
/* sudo "ALL" implies the SETENV tag */ |
|
Line 357 cmndspec : runasspec selinux cmndtag opcmnd {
|
Line 387 cmndspec : runasspec selinux cmndtag opcmnd {
|
| |
|
| opcmnd : cmnd { |
opcmnd : cmnd { |
| $$ = $1; |
$$ = $1; |
| $$->negated = FALSE; | $$->negated = false; |
| } |
} |
| | '!' cmnd { |
| '!' cmnd { |
| $$ = $2; |
$$ = $2; |
| $$->negated = TRUE; | $$->negated = true; |
| } |
} |
| ; |
; |
| |
|
|
Line 397 selinux : /* empty */ {
|
Line 427 selinux : /* empty */ {
|
| } |
} |
| ; |
; |
| |
|
| |
privsspec : PRIVS '=' WORD { |
| |
$$ = $3; |
| |
} |
| |
; |
| |
limitprivsspec : LIMITPRIVS '=' WORD { |
| |
$$ = $3; |
| |
} |
| |
; |
| |
|
| |
solarisprivs : /* empty */ { |
| |
$$.privs = NULL; |
| |
$$.limitprivs = NULL; |
| |
} |
| |
| privsspec { |
| |
$$.privs = $1; |
| |
$$.limitprivs = NULL; |
| |
} |
| |
| limitprivsspec { |
| |
$$.privs = NULL; |
| |
$$.limitprivs = $1; |
| |
} |
| |
| privsspec limitprivsspec { |
| |
$$.privs = $1; |
| |
$$.limitprivs = $2; |
| |
} |
| |
| limitprivsspec privsspec { |
| |
$$.limitprivs = $1; |
| |
$$.privs = $2; |
| |
} |
| |
|
| runasspec : /* empty */ { |
runasspec : /* empty */ { |
| $$ = NULL; |
$$ = NULL; |
| } |
} |
|
Line 405 runasspec : /* empty */ {
|
Line 465 runasspec : /* empty */ {
|
| } |
} |
| ; |
; |
| |
|
| runaslist : userlist { | runaslist : /* empty */ { |
| $$ = emalloc(sizeof(struct runascontainer)); | $$ = ecalloc(1, sizeof(struct runascontainer)); |
| | $$->runasusers = new_member(NULL, MYSELF); |
| | /* $$->runasgroups = NULL; */ |
| | } |
| | | userlist { |
| | $$ = ecalloc(1, sizeof(struct runascontainer)); |
| $$->runasusers = $1; |
$$->runasusers = $1; |
| $$->runasgroups = NULL; | /* $$->runasgroups = NULL; */ |
| } |
} |
| | userlist ':' grouplist { |
| userlist ':' grouplist { |
| $$ = emalloc(sizeof(struct runascontainer)); | $$ = ecalloc(1, sizeof(struct runascontainer)); |
| $$->runasusers = $1; |
$$->runasusers = $1; |
| $$->runasgroups = $3; |
$$->runasgroups = $3; |
| } |
} |
| | ':' grouplist { |
| ':' grouplist { |
| $$ = emalloc(sizeof(struct runascontainer)); | $$ = ecalloc(1, sizeof(struct runascontainer)); |
| $$->runasusers = NULL; | /* $$->runasusers = NULL; */ |
| $$->runasgroups = $2; |
$$->runasgroups = $2; |
| } |
} |
| |
| ':' { |
| |
$$ = ecalloc(1, sizeof(struct runascontainer)); |
| |
$$->runasusers = new_member(NULL, MYSELF); |
| |
/* $$->runasgroups = NULL; */ |
| |
} |
| ; |
; |
| |
|
| cmndtag : /* empty */ { |
cmndtag : /* empty */ { |
|
Line 427 cmndtag : /* empty */ {
|
Line 497 cmndtag : /* empty */ {
|
| $$.log_input = $$.log_output = UNSPEC; |
$$.log_input = $$.log_output = UNSPEC; |
| } |
} |
| | cmndtag NOPASSWD { |
| cmndtag NOPASSWD { |
| $$.nopasswd = TRUE; | $$.nopasswd = true; |
| } |
} |
| | cmndtag PASSWD { |
| cmndtag PASSWD { |
| $$.nopasswd = FALSE; | $$.nopasswd = false; |
| } |
} |
| | cmndtag NOEXEC { |
| cmndtag NOEXEC { |
| $$.noexec = TRUE; | $$.noexec = true; |
| } |
} |
| | cmndtag EXEC { |
| cmndtag EXEC { |
| $$.noexec = FALSE; | $$.noexec = false; |
| } |
} |
| | cmndtag SETENV { |
| cmndtag SETENV { |
| $$.setenv = TRUE; | $$.setenv = true; |
| } |
} |
| | cmndtag NOSETENV { |
| cmndtag NOSETENV { |
| $$.setenv = FALSE; | $$.setenv = false; |
| } |
} |
| | cmndtag LOG_INPUT { |
| cmndtag LOG_INPUT { |
| $$.log_input = TRUE; | $$.log_input = true; |
| } |
} |
| | cmndtag NOLOG_INPUT { |
| cmndtag NOLOG_INPUT { |
| $$.log_input = FALSE; | $$.log_input = false; |
| } |
} |
| | cmndtag LOG_OUTPUT { |
| cmndtag LOG_OUTPUT { |
| $$.log_output = TRUE; | $$.log_output = true; |
| } |
} |
| | cmndtag NOLOG_OUTPUT { |
| cmndtag NOLOG_OUTPUT { |
| $$.log_output = FALSE; | $$.log_output = false; |
| } |
} |
| ; |
; |
| |
|
|
Line 465 cmnd : ALL {
|
Line 535 cmnd : ALL {
|
| $$ = new_member($1, ALIAS); |
$$ = new_member($1, ALIAS); |
| } |
} |
| | COMMAND { |
| COMMAND { |
| struct sudo_command *c = emalloc(sizeof(*c)); | struct sudo_command *c = ecalloc(1, sizeof(*c)); |
| c->cmnd = $1.cmnd; |
c->cmnd = $1.cmnd; |
| c->args = $1.args; |
c->args = $1.args; |
| $$ = new_member((char *)c, COMMAND); |
$$ = new_member((char *)c, COMMAND); |
|
Line 547 userlist : opuser
|
Line 617 userlist : opuser
|
| |
|
| opuser : user { |
opuser : user { |
| $$ = $1; |
$$ = $1; |
| $$->negated = FALSE; | $$->negated = false; |
| } |
} |
| | '!' user { |
| '!' user { |
| $$ = $2; |
$$ = $2; |
| $$->negated = TRUE; | $$->negated = true; |
| } |
} |
| ; |
; |
| |
|
|
Line 581 grouplist : opgroup
|
Line 651 grouplist : opgroup
|
| |
|
| opgroup : group { |
opgroup : group { |
| $$ = $1; |
$$ = $1; |
| $$->negated = FALSE; | $$->negated = false; |
| } |
} |
| | '!' group { |
| '!' group { |
| $$ = $2; |
$$ = $2; |
| $$->negated = TRUE; | $$->negated = true; |
| } |
} |
| ; |
; |
| |
|
|
Line 605 static struct defaults *
|
Line 675 static struct defaults *
|
| new_default(char *var, char *val, int op) |
new_default(char *var, char *val, int op) |
| { |
{ |
| struct defaults *d; |
struct defaults *d; |
| |
debug_decl(new_default, SUDO_DEBUG_PARSER) |
| |
|
| d = emalloc(sizeof(struct defaults)); | d = ecalloc(1, sizeof(struct defaults)); |
| d->var = var; |
d->var = var; |
| d->val = val; |
d->val = val; |
| tq_init(&d->binding); |
tq_init(&d->binding); |
| d->type = 0; | /* d->type = 0; */ |
| d->op = op; |
d->op = op; |
| d->prev = d; |
d->prev = d; |
| d->next = NULL; | /* d->next = NULL; */ |
| |
|
| return d; | debug_return_ptr(d); |
| } |
} |
| |
|
| static struct member * |
static struct member * |
| new_member(char *name, int type) |
new_member(char *name, int type) |
| { |
{ |
| struct member *m; |
struct member *m; |
| |
debug_decl(new_member, SUDO_DEBUG_PARSER) |
| |
|
| m = emalloc(sizeof(struct member)); | m = ecalloc(1, sizeof(struct member)); |
| m->name = name; |
m->name = name; |
| m->type = type; |
m->type = type; |
| m->prev = m; |
m->prev = m; |
| m->next = NULL; | /* m->next = NULL; */ |
| |
|
| return m; | debug_return_ptr(m); |
| } |
} |
| |
|
| /* |
/* |
|
Line 642 add_defaults(int type, struct member *bmem, struct def
|
Line 714 add_defaults(int type, struct member *bmem, struct def
|
| { |
{ |
| struct defaults *d; |
struct defaults *d; |
| struct member_list binding; |
struct member_list binding; |
| |
debug_decl(add_defaults, SUDO_DEBUG_PARSER) |
| |
|
| /* |
/* |
| * We can only call list2tq once on bmem as it will zero |
* We can only call list2tq once on bmem as it will zero |
|
Line 657 add_defaults(int type, struct member *bmem, struct def
|
Line 730 add_defaults(int type, struct member *bmem, struct def
|
| d->binding = binding; |
d->binding = binding; |
| } |
} |
| tq_append(&defaults, defs); |
tq_append(&defaults, defs); |
| |
|
| |
debug_return; |
| } |
} |
| |
|
| /* |
/* |
|
Line 667 static void
|
Line 742 static void
|
| add_userspec(struct member *members, struct privilege *privs) |
add_userspec(struct member *members, struct privilege *privs) |
| { |
{ |
| struct userspec *u; |
struct userspec *u; |
| |
debug_decl(add_userspec, SUDO_DEBUG_PARSER) |
| |
|
| u = emalloc(sizeof(*u)); | u = ecalloc(1, sizeof(*u)); |
| list2tq(&u->users, members); |
list2tq(&u->users, members); |
| list2tq(&u->privileges, privs); |
list2tq(&u->privileges, privs); |
| u->prev = u; |
u->prev = u; |
| u->next = NULL; | /* u->next = NULL; */ |
| tq_append(&userspecs, u); |
tq_append(&userspecs, u); |
| |
|
| |
debug_return; |
| } |
} |
| |
|
| /* |
/* |
|
Line 681 add_userspec(struct member *members, struct privilege
|
Line 759 add_userspec(struct member *members, struct privilege
|
| * the current sudoers file to path. |
* the current sudoers file to path. |
| */ |
*/ |
| void |
void |
| init_parser(const char *path, int quiet) | init_parser(const char *path, bool quiet) |
| { |
{ |
| struct defaults *d; |
struct defaults *d; |
| struct member *m, *binding; |
struct member *m, *binding; |
|
Line 689 init_parser(const char *path, int quiet)
|
Line 767 init_parser(const char *path, int quiet)
|
| struct privilege *priv; |
struct privilege *priv; |
| struct cmndspec *cs; |
struct cmndspec *cs; |
| struct sudo_command *c; |
struct sudo_command *c; |
| |
debug_decl(init_parser, SUDO_DEBUG_PARSER) |
| |
|
| while ((us = tq_pop(&userspecs)) != NULL) { |
while ((us = tq_pop(&userspecs)) != NULL) { |
| while ((m = tq_pop(&us->users)) != NULL) { |
while ((m = tq_pop(&us->users)) != NULL) { |
|
Line 700 init_parser(const char *path, int quiet)
|
Line 779 init_parser(const char *path, int quiet)
|
| #ifdef HAVE_SELINUX |
#ifdef HAVE_SELINUX |
| char *role = NULL, *type = NULL; |
char *role = NULL, *type = NULL; |
| #endif /* HAVE_SELINUX */ |
#endif /* HAVE_SELINUX */ |
| |
#ifdef HAVE_PRIV_SET |
| |
char *privs = NULL, *limitprivs = NULL; |
| |
#endif /* HAVE_PRIV_SET */ |
| |
|
| while ((m = tq_pop(&priv->hostlist)) != NULL) { |
while ((m = tq_pop(&priv->hostlist)) != NULL) { |
| efree(m->name); |
efree(m->name); |
|
Line 717 init_parser(const char *path, int quiet)
|
Line 799 init_parser(const char *path, int quiet)
|
| efree(cs->type); |
efree(cs->type); |
| } |
} |
| #endif /* HAVE_SELINUX */ |
#endif /* HAVE_SELINUX */ |
| |
#ifdef HAVE_PRIV_SET |
| |
/* Only free the first instance of privs/limitprivs. */ |
| |
if (cs->privs != privs) { |
| |
privs = cs->privs; |
| |
efree(cs->privs); |
| |
} |
| |
if (cs->limitprivs != limitprivs) { |
| |
limitprivs = cs->limitprivs; |
| |
efree(cs->limitprivs); |
| |
} |
| |
#endif /* HAVE_PRIV_SET */ |
| if (tq_last(&cs->runasuserlist) != runasuser) { |
if (tq_last(&cs->runasuserlist) != runasuser) { |
| runasuser = tq_last(&cs->runasuserlist); |
runasuser = tq_last(&cs->runasuserlist); |
| while ((m = tq_pop(&cs->runasuserlist)) != NULL) { |
while ((m = tq_pop(&cs->runasuserlist)) != NULL) { |
|
Line 773 init_parser(const char *path, int quiet)
|
Line 866 init_parser(const char *path, int quiet)
|
| efree(sudoers); |
efree(sudoers); |
| sudoers = path ? estrdup(path) : NULL; |
sudoers = path ? estrdup(path) : NULL; |
| |
|
| parse_error = FALSE; | parse_error = false; |
| errorlineno = -1; |
errorlineno = -1; |
| errorfile = NULL; | errorfile = sudoers; |
| verbose = !quiet; | sudoers_warnings = !quiet; |
| | |
| | debug_return; |
| } |
} |