Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / gram.y
index 483d0c3a8627c7dc412327dbc87907db24391e86..0642802b57753a2a9c786fd717d3c9b798fe47bc 100644 (file)
@@ -1,6 +1,6 @@
 %{
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2012
+ * Copyright (c) 1996, 1998-2005, 2007-2013
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -25,7 +25,6 @@
 #include <config.h>
 
 #include <sys/types.h>
-#include <sys/param.h>
 #include <stdio.h>
 #ifdef STDC_HEADERS
 # include <stdlib.h>
@@ -44,6 +43,9 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
 #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
 # include <alloca.h>
 #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
@@ -52,7 +54,6 @@
 #include "sudoers.h" /* XXX */
 #include "parse.h"
 #include "toke.h"
-#include "gram.h"
 
 /*
  * We must define SIZE_MAX for yacc's skeleton.c.
@@ -73,7 +74,7 @@
 extern int sudolineno;
 extern int last_token;
 extern char *sudoers;
-static bool verbose = false;
+bool sudoers_warnings = true;
 bool parse_error = false;
 int errorlineno = -1;
 char *errorfile = NULL;
@@ -88,30 +89,7 @@ static void  add_defaults(int, struct member *, struct defaults *);
 static void  add_userspec(struct member *, struct privilege *);
 static struct defaults *new_default(char *, char *, int);
 static struct member *new_member(char *, int);
-       void  yyerror(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 (verbose && s != NULL) {
-       warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno);
-    }
-    parse_error = true;
-    debug_return;
-}
+static struct sudo_digest *new_digest(int, const char *);
 %}
 
 %union {
@@ -120,9 +98,11 @@ yyerror(const char *s)
     struct member *member;
     struct runascontainer *runas;
     struct privilege *privilege;
+    struct sudo_digest *digest;
     struct sudo_command command;
     struct cmndtag tag;
     struct selinux_info seinfo;
+    struct solaris_privs_info privinfo;
     char *string;
     int tok;
 }
@@ -135,6 +115,7 @@ yyerror(const char *s)
 %token <string>  NETGROUP              /* a netgroup (+NAME) */
 %token <string>  USERGROUP             /* a usergroup (%NAME) */
 %token <string>  WORD                  /* a word */
+%token <string>  DIGEST                        /* a SHA-2 digest */
 %token <tok>    DEFAULTS               /* Defaults entry */
 %token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
 %token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
@@ -161,6 +142,13 @@ yyerror(const char *s)
 %token <tok>    ERROR
 %token <tok>    TYPE                   /* SELinux type */
 %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>  cmndspeclist
@@ -168,6 +156,7 @@ yyerror(const char *s)
 %type <defaults>  defaults_list
 %type <member>   cmnd
 %type <member>   opcmnd
+%type <member>   digcmnd
 %type <member>   cmndlist
 %type <member>   host
 %type <member>   hostlist
@@ -186,6 +175,10 @@ yyerror(const char *s)
 %type <seinfo>   selinux
 %type <string>   rolespec
 %type <string>   typespec
+%type <privinfo>  solarisprivs
+%type <string>   privsspec
+%type <string>   limitprivsspec
+%type <digest>   digest
 
 %%
 
@@ -267,11 +260,11 @@ privileges        :       privilege
                ;
 
 privilege      :       hostlist '=' cmndspeclist {
-                           struct privilege *p = emalloc(sizeof(*p));
+                           struct privilege *p = ecalloc(1, sizeof(*p));
                            list2tq(&p->hostlist, $1);
                            list2tq(&p->cmndlist, $3);
                            p->prev = p;
-                           p->next = NULL;
+                           /* p->next = NULL; */
                            $$ = p;
                        }
                ;
@@ -313,6 +306,13 @@ cmndspeclist       :       cmndspec
                            if ($3->type == NULL)
                                $3->type = $3->prev->type;
 #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 */
                            if ($3->tags.nopasswd == UNSPEC)
                                $3->tags.nopasswd = $3->prev->tags.nopasswd;
@@ -336,8 +336,8 @@ cmndspeclist        :       cmndspec
                        }
                ;
 
-cmndspec       :       runasspec selinux cmndtag opcmnd {
-                           struct cmndspec *cs = emalloc(sizeof(*cs));
+cmndspec       :       runasspec selinux solarisprivs cmndtag digcmnd {
+                           struct cmndspec *cs = ecalloc(1, sizeof(*cs));
                            if ($1 != NULL) {
                                list2tq(&cs->runasuserlist, $1->runasusers);
                                list2tq(&cs->runasgrouplist, $1->runasgroups);
@@ -350,8 +350,12 @@ cmndspec   :       runasspec selinux cmndtag opcmnd {
                            cs->role = $2.role;
                            cs->type = $2.type;
 #endif
-                           cs->tags = $3;
-                           cs->cmnd = $4;
+#ifdef HAVE_PRIV_SET
+                           cs->privs = $3.privs;
+                           cs->limitprivs = $3.limitprivs;
+#endif
+                           cs->tags = $4;
+                           cs->cmnd = $5;
                            cs->prev = cs;
                            cs->next = NULL;
                            /* sudo "ALL" implies the SETENV tag */
@@ -362,6 +366,31 @@ 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 {
                            $$ = $1;
                            $$->negated = false;
@@ -404,6 +433,37 @@ 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 */ {
                            $$ = NULL;
                        }
@@ -412,21 +472,31 @@ runasspec :       /* empty */ {
                        }
                ;
 
-runaslist      :       userlist {
-                           $$ = emalloc(sizeof(struct runascontainer));
+runaslist      :       /* empty */ {
+                           $$ = ecalloc(1, sizeof(struct runascontainer));
+                           $$->runasusers = new_member(NULL, MYSELF);
+                           /* $$->runasgroups = NULL; */
+                       }
+               |       userlist {
+                           $$ = ecalloc(1, sizeof(struct runascontainer));
                            $$->runasusers = $1;
-                           $$->runasgroups = NULL;
+                           /* $$->runasgroups = NULL; */
                        }
                |       userlist ':' grouplist {
-                           $$ = emalloc(sizeof(struct runascontainer));
+                           $$ = ecalloc(1, sizeof(struct runascontainer));
                            $$->runasusers = $1;
                            $$->runasgroups = $3;
                        }
                |       ':' grouplist {
-                           $$ = emalloc(sizeof(struct runascontainer));
-                           $$->runasusers = NULL;
+                           $$ = ecalloc(1, sizeof(struct runascontainer));
+                           /* $$->runasusers = NULL; */
                            $$->runasgroups = $2;
                        }
+               |       ':' {
+                           $$ = ecalloc(1, sizeof(struct runascontainer));
+                           $$->runasusers = new_member(NULL, MYSELF);
+                           /* $$->runasgroups = NULL; */
+                       }
                ;
 
 cmndtag                :       /* empty */ {
@@ -472,7 +542,7 @@ cmnd                :       ALL {
                            $$ = new_member($1, ALIAS);
                        }
                |       COMMAND {
-                           struct sudo_command *c = emalloc(sizeof(*c));
+                           struct sudo_command *c = ecalloc(1, sizeof(*c));
                            c->cmnd = $1.cmnd;
                            c->args = $1.args;
                            $$ = new_member((char *)c, COMMAND);
@@ -486,7 +556,7 @@ hostaliases :       hostalias
 hostalias      :       ALIAS '=' hostlist {
                            char *s;
                            if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
-                               yyerror(s);
+                               sudoerserror(s);
                                YYERROR;
                            }
                        }
@@ -506,14 +576,14 @@ cmndaliases       :       cmndalias
 cmndalias      :       ALIAS '=' cmndlist {
                            char *s;
                            if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
-                               yyerror(s);
+                               sudoerserror(s);
                                YYERROR;
                            }
                        }
                ;
 
-cmndlist       :       opcmnd
-               |       cmndlist ',' opcmnd {
+cmndlist       :       digcmnd
+               |       cmndlist ',' digcmnd {
                            list_append($1, $3);
                            $$ = $1;
                        }
@@ -526,7 +596,7 @@ runasaliases        :       runasalias
 runasalias     :       ALIAS '=' userlist {
                            char *s;
                            if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
-                               yyerror(s);
+                               sudoerserror(s);
                                YYERROR;
                            }
                        }
@@ -539,7 +609,7 @@ useraliases :       useralias
 useralias      :       ALIAS '=' userlist {
                            char *s;
                            if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
-                               yyerror(s);
+                               sudoerserror(s);
                                YYERROR;
                            }
                        }
@@ -608,20 +678,52 @@ 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 *
 new_default(char *var, char *val, int op)
 {
     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->val = val;
     tq_init(&d->binding);
-    d->type = 0;
+    /* d->type = 0; */
     d->op = op;
     d->prev = d;
-    d->next = NULL;
+    /* d->next = NULL; */
 
     debug_return_ptr(d);
 }
@@ -632,15 +734,28 @@ new_member(char *name, int type)
     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->type = type;
     m->prev = m;
-    m->next = NULL;
+    /* m->next = NULL; */
 
     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.
  * The binding, if non-NULL, specifies a list of hosts, users, or
@@ -681,11 +796,11 @@ add_userspec(struct member *members, struct privilege *privs)
     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->privileges, privs);
     u->prev = u;
-    u->next = NULL;
+    /* u->next = NULL; */
     tq_append(&userspecs, u);
 
     debug_return;
@@ -696,7 +811,7 @@ add_userspec(struct member *members, struct privilege *privs)
  * the current sudoers file to path.
  */
 void
-init_parser(const char *path, int quiet)
+init_parser(const char *path, bool quiet)
 {
     struct defaults *d;
     struct member *m, *binding;
@@ -716,6 +831,9 @@ init_parser(const char *path, int quiet)
 #ifdef HAVE_SELINUX
            char *role = NULL, *type = NULL;
 #endif /* HAVE_SELINUX */
+#ifdef HAVE_PRIV_SET
+           char *privs = NULL, *limitprivs = NULL;
+#endif /* HAVE_PRIV_SET */
 
            while ((m = tq_pop(&priv->hostlist)) != NULL) {
                efree(m->name);
@@ -733,6 +851,17 @@ init_parser(const char *path, int quiet)
                    efree(cs->type);
                }
 #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) {
                    runasuser = tq_last(&cs->runasuserlist);
                    while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
@@ -792,7 +921,7 @@ init_parser(const char *path, int quiet)
     parse_error = false;
     errorlineno = -1;
     errorfile = sudoers;
-    verbose = !quiet;
+    sudoers_warnings = !quiet;
 
     debug_return;
 }