version 1.1.1.2, 2012/05/29 12:26:49
|
version 1.1.1.4, 2013/07/22 10:46:12
|
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 25
|
Line 25
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
# include <stdlib.h> |
# include <stdlib.h> |
Line 44
|
Line 43
|
#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 54
|
#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 88 static void add_defaults(int, struct member *, struct
|
Line 89 static void add_defaults(int, struct member *, struct
|
static void add_userspec(struct member *, struct privilege *); |
static void add_userspec(struct member *, struct privilege *); |
static struct defaults *new_default(char *, char *, int); |
static struct defaults *new_default(char *, char *, int); |
static struct member *new_member(char *, int); |
static struct member *new_member(char *, int); |
void yyerror(const char *); | static struct sudo_digest *new_digest(int, const char *); |
| |
void | |
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. */ | |
if (errorlineno == -1) { | |
errorlineno = sudolineno; | |
errorfile = estrdup(sudoers); | |
} | |
if (trace_print != NULL) { | |
LEXTRACE("<*> "); | |
} else if (sudoers_warnings && s != NULL) { | |
warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno); | |
} | |
parse_error = true; | |
debug_return; | |
} | |
%} |
%} |
|
|
%union { |
%union { |
Line 120 yyerror(const char *s)
|
Line 98 yyerror(const char *s)
|
struct member *member; |
struct member *member; |
struct runascontainer *runas; |
struct runascontainer *runas; |
struct privilege *privilege; |
struct privilege *privilege; |
|
struct sudo_digest *digest; |
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 135 yyerror(const char *s)
|
Line 115 yyerror(const char *s)
|
%token <string> NETGROUP /* a netgroup (+NAME) */ |
%token <string> NETGROUP /* a netgroup (+NAME) */ |
%token <string> USERGROUP /* a usergroup (%NAME) */ |
%token <string> USERGROUP /* a usergroup (%NAME) */ |
%token <string> WORD /* a word */ |
%token <string> WORD /* a word */ |
|
%token <string> DIGEST /* a SHA-2 digest */ |
%token <tok> DEFAULTS /* Defaults entry */ |
%token <tok> DEFAULTS /* Defaults entry */ |
%token <tok> DEFAULTS_HOST /* Host-specific defaults entry */ |
%token <tok> DEFAULTS_HOST /* Host-specific defaults entry */ |
%token <tok> DEFAULTS_USER /* User-specific defaults entry */ |
%token <tok> DEFAULTS_USER /* User-specific defaults entry */ |
Line 161 yyerror(const char *s)
|
Line 142 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 */ |
|
%token <tok> SHA224 /* sha224 digest */ |
|
%token <tok> SHA256 /* sha256 digest */ |
|
%token <tok> SHA384 /* sha384 digest */ |
|
%token <tok> SHA512 /* sha512 digest */ |
|
|
%type <cmndspec> cmndspec |
%type <cmndspec> cmndspec |
%type <cmndspec> cmndspeclist |
%type <cmndspec> cmndspeclist |
Line 168 yyerror(const char *s)
|
Line 156 yyerror(const char *s)
|
%type <defaults> defaults_list |
%type <defaults> defaults_list |
%type <member> cmnd |
%type <member> cmnd |
%type <member> opcmnd |
%type <member> opcmnd |
|
%type <member> digcmnd |
%type <member> cmndlist |
%type <member> cmndlist |
%type <member> host |
%type <member> host |
%type <member> hostlist |
%type <member> hostlist |
Line 186 yyerror(const char *s)
|
Line 175 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 |
|
%type <digest> digest |
|
|
%% |
%% |
|
|
Line 313 cmndspeclist : cmndspec
|
Line 306 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 336 cmndspeclist : cmndspec
|
Line 336 cmndspeclist : cmndspec
|
} |
} |
; |
; |
|
|
cmndspec : runasspec selinux cmndtag opcmnd { | 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); |
list2tq(&cs->runasuserlist, $1->runasusers); |
Line 350 cmndspec : runasspec selinux cmndtag opcmnd {
|
Line 350 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 362 cmndspec : runasspec selinux cmndtag opcmnd {
|
Line 366 cmndspec : runasspec selinux cmndtag opcmnd {
|
} |
} |
; |
; |
|
|
|
digest : SHA224 ':' DIGEST { |
|
$$ = new_digest(SUDO_DIGEST_SHA224, $3); |
|
} |
|
| SHA256 ':' DIGEST { |
|
$$ = new_digest(SUDO_DIGEST_SHA256, $3); |
|
} |
|
| SHA384 ':' DIGEST { |
|
$$ = new_digest(SUDO_DIGEST_SHA384, $3); |
|
} |
|
| SHA512 ':' DIGEST { |
|
$$ = new_digest(SUDO_DIGEST_SHA512, $3); |
|
} |
|
; |
|
|
|
digcmnd : opcmnd { |
|
$$ = $1; |
|
} |
|
| digest opcmnd { |
|
/* XXX - yuck */ |
|
struct sudo_command *c = (struct sudo_command *)($2->name); |
|
c->digest = $1; |
|
$$ = $2; |
|
} |
|
; |
|
|
opcmnd : cmnd { |
opcmnd : cmnd { |
$$ = $1; |
$$ = $1; |
$$->negated = false; |
$$->negated = false; |
Line 404 selinux : /* empty */ {
|
Line 433 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 412 runasspec : /* empty */ {
|
Line 472 runasspec : /* empty */ {
|
} |
} |
; |
; |
|
|
runaslist : userlist { | runaslist : /* empty */ { |
$$ = ecalloc(1, 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; */ |
} |
} |
Line 427 runaslist : userlist {
|
Line 492 runaslist : userlist {
|
/* $$->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 486 hostaliases : hostalias
|
Line 556 hostaliases : hostalias
|
hostalias : ALIAS '=' hostlist { |
hostalias : ALIAS '=' hostlist { |
char *s; |
char *s; |
if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) { |
if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) { |
yyerror(s); | sudoerserror(s); |
YYERROR; |
YYERROR; |
} |
} |
} |
} |
Line 506 cmndaliases : cmndalias
|
Line 576 cmndaliases : cmndalias
|
cmndalias : ALIAS '=' cmndlist { |
cmndalias : ALIAS '=' cmndlist { |
char *s; |
char *s; |
if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) { |
if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) { |
yyerror(s); | sudoerserror(s); |
YYERROR; |
YYERROR; |
} |
} |
} |
} |
; |
; |
|
|
cmndlist : opcmnd | cmndlist : digcmnd |
| cmndlist ',' opcmnd { | | cmndlist ',' digcmnd { |
list_append($1, $3); |
list_append($1, $3); |
$$ = $1; |
$$ = $1; |
} |
} |
Line 526 runasaliases : runasalias
|
Line 596 runasaliases : runasalias
|
runasalias : ALIAS '=' userlist { |
runasalias : ALIAS '=' userlist { |
char *s; |
char *s; |
if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) { |
if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) { |
yyerror(s); | sudoerserror(s); |
YYERROR; |
YYERROR; |
} |
} |
} |
} |
Line 539 useraliases : useralias
|
Line 609 useraliases : useralias
|
useralias : ALIAS '=' userlist { |
useralias : ALIAS '=' userlist { |
char *s; |
char *s; |
if ((s = alias_add($1, USERALIAS, $3)) != NULL) { |
if ((s = alias_add($1, USERALIAS, $3)) != NULL) { |
yyerror(s); | sudoerserror(s); |
YYERROR; |
YYERROR; |
} |
} |
} |
} |
Line 608 group : ALIAS {
|
Line 678 group : ALIAS {
|
; |
; |
|
|
%% |
%% |
|
void |
|
sudoerserror(const char *s) |
|
{ |
|
debug_decl(sudoerserror, 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. */ |
|
if (errorlineno == -1) { |
|
errorlineno = sudolineno; |
|
errorfile = estrdup(sudoers); |
|
} |
|
if (sudoers_warnings && s != NULL) { |
|
LEXTRACE("<*> "); |
|
#ifndef TRACELEXER |
|
if (trace_print == NULL || trace_print == sudoers_trace_print) { |
|
const char fmt[] = ">>> %s: %s near line %d <<<\n"; |
|
int oldlocale; |
|
|
|
/* Warnings are displayed in the user's locale. */ |
|
sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale); |
|
sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), sudolineno); |
|
sudoers_setlocale(oldlocale, NULL); |
|
} |
|
#endif |
|
} |
|
parse_error = true; |
|
debug_return; |
|
} |
|
|
static struct defaults * |
static struct defaults * |
new_default(char *var, char *val, int op) |
new_default(char *var, char *val, int op) |
{ |
{ |
Line 641 new_member(char *name, int type)
|
Line 743 new_member(char *name, int type)
|
debug_return_ptr(m); |
debug_return_ptr(m); |
} |
} |
|
|
|
struct sudo_digest * |
|
new_digest(int digest_type, const char *digest_str) |
|
{ |
|
struct sudo_digest *dig; |
|
debug_decl(new_digest, SUDO_DEBUG_PARSER) |
|
|
|
dig = emalloc(sizeof(*dig)); |
|
dig->digest_type = digest_type; |
|
dig->digest_str = estrdup(digest_str); |
|
|
|
debug_return_ptr(dig); |
|
} |
|
|
/* |
/* |
* Add a list of defaults structures to the defaults list. |
* Add a list of defaults structures to the defaults list. |
* The binding, if non-NULL, specifies a list of hosts, users, or |
* The binding, if non-NULL, specifies a list of hosts, users, or |
Line 696 add_userspec(struct member *members, struct privilege
|
Line 811 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 716 init_parser(const char *path, int quiet)
|
Line 831 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 733 init_parser(const char *path, int quiet)
|
Line 851 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) { |