| version 1.1.1.4, 2013/07/22 10:46:12 | version 1.1.1.5, 2014/06/15 16:12:54 | 
| Line 71 | Line 71 | 
 | /* | /* | 
 | * Globals | * Globals | 
 | */ | */ | 
 | extern int sudolineno; |  | 
 | extern int last_token; |  | 
 | extern char *sudoers; |  | 
 | bool sudoers_warnings = true; | bool sudoers_warnings = true; | 
 | bool parse_error = false; | bool parse_error = false; | 
 | int errorlineno = -1; | int errorlineno = -1; | 
| char *errorfile = NULL; | const char *errorfile = NULL; | 
 |  |  | 
| struct defaults_list defaults; | struct defaults_list defaults = TAILQ_HEAD_INITIALIZER(defaults); | 
| struct userspec_list userspecs; | struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs); | 
 |  |  | 
 | /* | /* | 
 | * Local protoypes | * Local protoypes | 
| Line 230  entry  : COMMENT { | Line 227  entry  : COMMENT { | 
 |  |  | 
 | defaults_list   :       defaults_entry | defaults_list   :       defaults_entry | 
 | |       defaults_list ',' defaults_entry { | |       defaults_list ',' defaults_entry { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
| Line 254  defaults_entry : DEFVAR { | Line 251  defaults_entry : DEFVAR { | 
 |  |  | 
 | privileges      :       privilege | privileges      :       privilege | 
 | |       privileges ':' privilege { | |       privileges ':' privilege { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
 |  |  | 
 | privilege       :       hostlist '=' cmndspeclist { | privilege       :       hostlist '=' cmndspeclist { | 
 | struct privilege *p = ecalloc(1, sizeof(*p)); | struct privilege *p = ecalloc(1, sizeof(*p)); | 
| list2tq(&p->hostlist, $1); | HLTQ_TO_TAILQ(&p->hostlist, $1, entries); | 
| list2tq(&p->cmndlist, $3); | HLTQ_TO_TAILQ(&p->cmndlist, $3, entries); | 
| p->prev = p; | HLTQ_INIT(p, entries); | 
| /* p->next = NULL; */ |  | 
 | $$ = p; | $$ = p; | 
 | } | } | 
 | ; | ; | 
| Line 298  host  : ALIAS { | Line 294  host  : ALIAS { | 
 |  |  | 
 | cmndspeclist    :       cmndspec | cmndspeclist    :       cmndspec | 
 | |       cmndspeclist ',' cmndspec { | |       cmndspeclist ',' cmndspec { | 
| list_append($1, $3); | struct cmndspec *prev; | 
|  | prev = HLTQ_LAST($1, cmndspec, entries); | 
|  | HLTQ_CONCAT($1, $3, entries); | 
 | #ifdef HAVE_SELINUX | #ifdef HAVE_SELINUX | 
 | /* propagate role and type */ | /* propagate role and type */ | 
 | if ($3->role == NULL) | if ($3->role == NULL) | 
| $3->role = $3->prev->role; | $3->role = prev->role; | 
 | if ($3->type == NULL) | if ($3->type == NULL) | 
| $3->type = $3->prev->type; | $3->type = prev->type; | 
 | #endif /* HAVE_SELINUX */ | #endif /* HAVE_SELINUX */ | 
 | #ifdef HAVE_PRIV_SET | #ifdef HAVE_PRIV_SET | 
 | /* propagate privs & limitprivs */ | /* propagate privs & limitprivs */ | 
 | if ($3->privs == NULL) | if ($3->privs == NULL) | 
| $3->privs = $3->prev->privs; | $3->privs = prev->privs; | 
 | if ($3->limitprivs == NULL) | if ($3->limitprivs == NULL) | 
| $3->limitprivs = $3->prev->limitprivs; | $3->limitprivs = prev->limitprivs; | 
 | #endif /* HAVE_PRIV_SET */ | #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 = prev->tags.nopasswd; | 
 | if ($3->tags.noexec == UNSPEC) | if ($3->tags.noexec == UNSPEC) | 
| $3->tags.noexec = $3->prev->tags.noexec; | $3->tags.noexec = prev->tags.noexec; | 
 | if ($3->tags.setenv == UNSPEC && | if ($3->tags.setenv == UNSPEC && | 
| $3->prev->tags.setenv != IMPLIED) | prev->tags.setenv != IMPLIED) | 
| $3->tags.setenv = $3->prev->tags.setenv; | $3->tags.setenv = prev->tags.setenv; | 
 | if ($3->tags.log_input == UNSPEC) | if ($3->tags.log_input == UNSPEC) | 
| $3->tags.log_input = $3->prev->tags.log_input; | $3->tags.log_input = prev->tags.log_input; | 
 | if ($3->tags.log_output == UNSPEC) | if ($3->tags.log_output == UNSPEC) | 
| $3->tags.log_output = $3->prev->tags.log_output; | $3->tags.log_output = prev->tags.log_output; | 
| if ((tq_empty(&$3->runasuserlist) && | if (($3->runasuserlist == NULL && | 
| tq_empty(&$3->runasgrouplist)) && | $3->runasgrouplist == NULL) && | 
| (!tq_empty(&$3->prev->runasuserlist) || | (prev->runasuserlist != NULL || | 
| !tq_empty(&$3->prev->runasgrouplist))) { | prev->runasgrouplist != NULL)) { | 
| $3->runasuserlist = $3->prev->runasuserlist; | $3->runasuserlist = prev->runasuserlist; | 
| $3->runasgrouplist = $3->prev->runasgrouplist; | $3->runasgrouplist = prev->runasgrouplist; | 
 | } | } | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
| Line 339  cmndspeclist : cmndspec | Line 337  cmndspeclist : cmndspec | 
 | cmndspec        :       runasspec selinux solarisprivs cmndtag digcmnd { | cmndspec        :       runasspec selinux solarisprivs cmndtag digcmnd { | 
 | struct cmndspec *cs = ecalloc(1, sizeof(*cs)); | struct cmndspec *cs = ecalloc(1, sizeof(*cs)); | 
 | if ($1 != NULL) { | if ($1 != NULL) { | 
| list2tq(&cs->runasuserlist, $1->runasusers); | if ($1->runasusers != NULL) { | 
| list2tq(&cs->runasgrouplist, $1->runasgroups); | cs->runasuserlist = | 
|  | emalloc(sizeof(*cs->runasuserlist)); | 
|  | HLTQ_TO_TAILQ(cs->runasuserlist, | 
|  | $1->runasusers, entries); | 
|  | } | 
|  | if ($1->runasgroups != NULL) { | 
|  | cs->runasgrouplist = | 
|  | emalloc(sizeof(*cs->runasgrouplist)); | 
|  | HLTQ_TO_TAILQ(cs->runasgrouplist, | 
|  | $1->runasgroups, entries); | 
|  | } | 
 | efree($1); | efree($1); | 
 | } else { |  | 
 | tq_init(&cs->runasuserlist); |  | 
 | tq_init(&cs->runasgrouplist); |  | 
 | } | } | 
 | #ifdef HAVE_SELINUX | #ifdef HAVE_SELINUX | 
 | cs->role = $2.role; | cs->role = $2.role; | 
| Line 356  cmndspec : runasspec selinux solarisprivs cmndtag digc | Line 361  cmndspec : runasspec selinux solarisprivs cmndtag digc | 
 | #endif | #endif | 
 | cs->tags = $4; | cs->tags = $4; | 
 | cs->cmnd = $5; | cs->cmnd = $5; | 
| cs->prev = cs; | HLTQ_INIT(cs, entries); | 
| cs->next = NULL; |  | 
 | /* sudo "ALL" implies the SETENV tag */ | /* sudo "ALL" implies the SETENV tag */ | 
 | if (cs->cmnd->type == ALL && !cs->cmnd->negated && | if (cs->cmnd->type == ALL && !cs->cmnd->negated && | 
 | cs->tags.setenv == UNSPEC) | cs->tags.setenv == UNSPEC) | 
| Line 564  hostalias : ALIAS '=' hostlist { | Line 568  hostalias : ALIAS '=' hostlist { | 
 |  |  | 
 | hostlist        :       ophost | hostlist        :       ophost | 
 | |       hostlist ',' ophost { | |       hostlist ',' ophost { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
| Line 584  cmndalias : ALIAS '=' cmndlist { | Line 588  cmndalias : ALIAS '=' cmndlist { | 
 |  |  | 
 | cmndlist        :       digcmnd | cmndlist        :       digcmnd | 
 | |       cmndlist ',' digcmnd { | |       cmndlist ',' digcmnd { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
| Line 617  useralias : ALIAS '=' userlist { | Line 621  useralias : ALIAS '=' userlist { | 
 |  |  | 
 | userlist        :       opuser | userlist        :       opuser | 
 | |       userlist ',' opuser { | |       userlist ',' opuser { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
| Line 651  user  : ALIAS { | Line 655  user  : ALIAS { | 
 |  |  | 
 | grouplist       :       opgroup | grouplist       :       opgroup | 
 | |       grouplist ',' opgroup { | |       grouplist ',' opgroup { | 
| list_append($1, $3); | HLTQ_CONCAT($1, $3, entries); | 
 | $$ = $1; | $$ = $1; | 
 | } | } | 
 | ; | ; | 
| Line 719  new_default(char *var, char *val, int op) | Line 723  new_default(char *var, char *val, int op) | 
 | d = ecalloc(1, 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); |  | 
 | /* d->type = 0; */ | /* d->type = 0; */ | 
 | d->op = op; | d->op = op; | 
| d->prev = d; | /* d->binding = NULL */ | 
| /* d->next = NULL; */ | HLTQ_INIT(d, entries); | 
 |  |  | 
 | debug_return_ptr(d); | debug_return_ptr(d); | 
 | } | } | 
| Line 737  new_member(char *name, int type) | Line 740  new_member(char *name, int type) | 
 | m = ecalloc(1, sizeof(struct member)); | m = ecalloc(1, sizeof(struct member)); | 
 | m->name = name; | m->name = name; | 
 | m->type = type; | m->type = type; | 
| m->prev = m; | HLTQ_INIT(m, entries); | 
| /* m->next = NULL; */ |  | 
 |  |  | 
 | debug_return_ptr(m); | debug_return_ptr(m); | 
 | } | } | 
| Line 765  static void | Line 767  static void | 
 | add_defaults(int type, struct member *bmem, struct defaults *defs) | add_defaults(int type, struct member *bmem, struct defaults *defs) | 
 | { | { | 
 | struct defaults *d; | struct defaults *d; | 
| struct member_list binding; | struct member_list *binding; | 
 | debug_decl(add_defaults, SUDO_DEBUG_PARSER) | debug_decl(add_defaults, SUDO_DEBUG_PARSER) | 
 |  |  | 
| /* | if (defs != NULL) { | 
| * We can only call list2tq once on bmem as it will zero | /* | 
| * out the prev pointer when it consumes bmem. | * We use a single binding for each entry in defs. | 
| */ | */ | 
| list2tq(&binding, bmem); | binding = emalloc(sizeof(*binding)); | 
|  | if (bmem != NULL) | 
|  | HLTQ_TO_TAILQ(binding, bmem, entries); | 
|  | else | 
|  | TAILQ_INIT(binding); | 
 |  |  | 
| /* | /* | 
| * Set type and binding (who it applies to) for new entries. | * Set type and binding (who it applies to) for new entries. | 
| */ | * Then add to the global defaults list. | 
| for (d = defs; d != NULL; d = d->next) { | */ | 
| d->type = type; | HLTQ_FOREACH(d, defs, entries) { | 
| d->binding = binding; | d->type = type; | 
|  | d->binding = binding; | 
|  | } | 
|  | TAILQ_CONCAT_HLTQ(&defaults, defs, entries); | 
 | } | } | 
 | tq_append(&defaults, defs); |  | 
 |  |  | 
 | debug_return; | debug_return; | 
 | } | } | 
 |  |  | 
 | /* | /* | 
 | * Allocate a new struct userspec, populate it, and insert it at the | * Allocate a new struct userspec, populate it, and insert it at the | 
| * and of the userspecs list. | * end of the userspecs list. | 
 | */ | */ | 
 | static void | static void | 
 | add_userspec(struct member *members, struct privilege *privs) | add_userspec(struct member *members, struct privilege *privs) | 
| Line 797  add_userspec(struct member *members, struct privilege | Line 805  add_userspec(struct member *members, struct privilege | 
 | debug_decl(add_userspec, SUDO_DEBUG_PARSER) | debug_decl(add_userspec, SUDO_DEBUG_PARSER) | 
 |  |  | 
 | u = ecalloc(1, sizeof(*u)); | u = ecalloc(1, sizeof(*u)); | 
| list2tq(&u->users, members); | HLTQ_TO_TAILQ(&u->users, members, entries); | 
| list2tq(&u->privileges, privs); | HLTQ_TO_TAILQ(&u->privileges, privs, entries); | 
| u->prev = u; | TAILQ_INSERT_TAIL(&userspecs, u, entries); | 
| /* u->next = NULL; */ |  | 
| tq_append(&userspecs, u); |  | 
 |  |  | 
 | debug_return; | debug_return; | 
 | } | } | 
| Line 813  add_userspec(struct member *members, struct privilege | Line 819  add_userspec(struct member *members, struct privilege | 
 | void | void | 
 | init_parser(const char *path, bool quiet) | init_parser(const char *path, bool quiet) | 
 | { | { | 
| struct defaults *d; | struct member_list *binding; | 
| struct member *m, *binding; | struct defaults *d, *d_next; | 
| struct userspec *us; | struct userspec *us, *us_next; | 
| struct privilege *priv; |  | 
| struct cmndspec *cs; |  | 
| struct sudo_command *c; |  | 
 | debug_decl(init_parser, SUDO_DEBUG_PARSER) | debug_decl(init_parser, SUDO_DEBUG_PARSER) | 
 |  |  | 
| while ((us = tq_pop(&userspecs)) != NULL) { | TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) { | 
| while ((m = tq_pop(&us->users)) != NULL) { | struct member *m, *m_next; | 
|  | struct privilege *priv, *priv_next; | 
|  |  | 
|  | TAILQ_FOREACH_SAFE(m, &us->users, entries, m_next) { | 
 | efree(m->name); | efree(m->name); | 
 | efree(m); | efree(m); | 
 | } | } | 
| while ((priv = tq_pop(&us->privileges)) != NULL) { | TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, priv_next) { | 
| struct member *runasuser = NULL, *runasgroup = NULL; | struct member_list *runasuserlist = NULL, *runasgrouplist = NULL; | 
|  | struct cmndspec *cs, *cs_next; | 
 | #ifdef HAVE_SELINUX | #ifdef HAVE_SELINUX | 
 | char *role = NULL, *type = NULL; | char *role = NULL, *type = NULL; | 
 | #endif /* HAVE_SELINUX */ | #endif /* HAVE_SELINUX */ | 
| Line 835  init_parser(const char *path, bool quiet) | Line 842  init_parser(const char *path, bool quiet) | 
 | char *privs = NULL, *limitprivs = NULL; | char *privs = NULL, *limitprivs = NULL; | 
 | #endif /* HAVE_PRIV_SET */ | #endif /* HAVE_PRIV_SET */ | 
 |  |  | 
| while ((m = tq_pop(&priv->hostlist)) != NULL) { | TAILQ_FOREACH_SAFE(m, &priv->hostlist, entries, m_next) { | 
 | efree(m->name); | efree(m->name); | 
 | efree(m); | efree(m); | 
 | } | } | 
| while ((cs = tq_pop(&priv->cmndlist)) != NULL) { | TAILQ_FOREACH_SAFE(cs, &priv->cmndlist, entries, cs_next) { | 
 | #ifdef HAVE_SELINUX | #ifdef HAVE_SELINUX | 
 | /* Only free the first instance of a role/type. */ | /* Only free the first instance of a role/type. */ | 
 | if (cs->role != role) { | if (cs->role != role) { | 
| Line 862  init_parser(const char *path, bool quiet) | Line 869  init_parser(const char *path, bool quiet) | 
 | efree(cs->limitprivs); | efree(cs->limitprivs); | 
 | } | } | 
 | #endif /* HAVE_PRIV_SET */ | #endif /* HAVE_PRIV_SET */ | 
| if (tq_last(&cs->runasuserlist) != runasuser) { | /* Only free the first instance of runas user/group lists. */ | 
| runasuser = tq_last(&cs->runasuserlist); | if (cs->runasuserlist && cs->runasuserlist != runasuserlist) { | 
| while ((m = tq_pop(&cs->runasuserlist)) != NULL) { | runasuserlist = cs->runasuserlist; | 
|  | TAILQ_FOREACH_SAFE(m, runasuserlist, entries, m_next) { | 
 | efree(m->name); | efree(m->name); | 
 | efree(m); | efree(m); | 
 | } | } | 
 |  | efree(runasuserlist); | 
 | } | } | 
| if (tq_last(&cs->runasgrouplist) != runasgroup) { | if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) { | 
| runasgroup = tq_last(&cs->runasgrouplist); | runasgrouplist = cs->runasgrouplist; | 
| while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { | TAILQ_FOREACH_SAFE(m, runasgrouplist, entries, m_next) { | 
 | efree(m->name); | efree(m->name); | 
 | efree(m); | efree(m); | 
 | } | } | 
 |  | efree(runasgrouplist); | 
 | } | } | 
 | if (cs->cmnd->type == COMMAND) { | if (cs->cmnd->type == COMMAND) { | 
| c = (struct sudo_command *) cs->cmnd->name; | struct sudo_command *c = | 
|  | (struct sudo_command *) cs->cmnd->name; | 
 | efree(c->cmnd); | efree(c->cmnd); | 
 | efree(c->args); | efree(c->args); | 
 | } | } | 
| Line 889  init_parser(const char *path, bool quiet) | Line 900  init_parser(const char *path, bool quiet) | 
 | } | } | 
 | efree(us); | efree(us); | 
 | } | } | 
| tq_init(&userspecs); | TAILQ_INIT(&userspecs); | 
 |  |  | 
 | binding = NULL; | binding = NULL; | 
| while ((d = tq_pop(&defaults)) != NULL) { | TAILQ_FOREACH_SAFE(d, &defaults, entries, d_next) { | 
| if (tq_last(&d->binding) != binding) { | if (d->binding != binding) { | 
| binding = tq_last(&d->binding); | struct member *m, *m_next; | 
| while ((m = tq_pop(&d->binding)) != NULL) { |  | 
|  | binding = d->binding; | 
|  | TAILQ_FOREACH_SAFE(m, d->binding, entries, m_next) { | 
 | if (m->type == COMMAND) { | if (m->type == COMMAND) { | 
| c = (struct sudo_command *) m->name; | struct sudo_command *c = | 
|  | (struct sudo_command *) m->name; | 
 | efree(c->cmnd); | efree(c->cmnd); | 
 | efree(c->args); | efree(c->args); | 
 | } | } | 
 | efree(m->name); | efree(m->name); | 
 | efree(m); | efree(m); | 
 | } | } | 
 |  | efree(d->binding); | 
 | } | } | 
 | efree(d->var); | efree(d->var); | 
 | efree(d->val); | efree(d->val); | 
 | efree(d); | efree(d); | 
 | } | } | 
| tq_init(&defaults); | TAILQ_INIT(&defaults); | 
 |  |  | 
 | init_aliases(); | init_aliases(); | 
 |  |  |