2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-18 14:05:05 +00:00
Files
sudo/parse.yacc

706 lines
15 KiB
Plaintext
Raw Normal View History

1993-03-02 16:33:11 +00:00
%{
/*
1996-01-14 20:16:01 +00:00
* CU sudo version 1.4
1993-03-02 16:33:11 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
1995-03-29 04:12:17 +00:00
* Please send bugs, changes, problems to sudo-bugs@cs.colorado.edu
*
*******************************************************************
*
* parse.yacc -- yacc parser and alias manipulation routines for sudo.
*
* Chris Jepeway <jepeway@cs.utk.edu>
1993-03-02 16:33:11 +00:00
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif /* lint */
1994-05-28 17:21:11 +00:00
#include "config.h"
1993-03-02 16:33:11 +00:00
#include <stdio.h>
1995-03-29 22:38:16 +00:00
#ifdef STDC_HEADERS
#include <stdlib.h>
#endif /* STDC_HEADERS */
1994-08-30 22:30:00 +00:00
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
1995-11-21 02:13:59 +00:00
#include <pwd.h>
1993-03-02 16:33:11 +00:00
#include <sys/types.h>
1993-09-04 19:42:19 +00:00
#include <sys/param.h>
1994-08-12 02:00:39 +00:00
#include <netinet/in.h>
1995-03-24 03:32:53 +00:00
#ifdef HAVE_STRING_H
#include <string.h>
#endif /* HAVE_STRING_H */
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
1995-03-24 03:32:53 +00:00
#include <malloc.h>
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
#ifdef HAVE_LSEARCH
1995-03-24 03:32:53 +00:00
#include <search.h>
#endif /* HAVE_LSEARCH */
1995-03-24 03:32:53 +00:00
#include <options.h>
1996-03-11 01:15:08 +00:00
#include "sudo.h"
1993-03-02 16:33:11 +00:00
#ifndef HAVE_LSEARCH
1995-09-13 01:44:35 +00:00
#include "emul/search.h"
#endif /* HAVE_LSEARCH */
1996-03-11 01:15:08 +00:00
#ifndef HAVE_STRCASECMP
#define strcasecmp(a,b) strcmp(a,b)
#endif /* !HAVE_STRCASECMP */
/*
* Globals
*/
1995-03-24 03:32:53 +00:00
extern int sudolineno, parse_error;
int errorlineno = -1;
1995-05-02 03:33:26 +00:00
int clearaliases = 1;
1995-06-14 08:42:57 +00:00
int printmatches = 0;
1995-03-24 03:32:53 +00:00
/*
* Alias types
*/
#define HOST 1
#define CMND 2
1995-04-09 02:27:40 +00:00
#define USER 3
1995-03-24 03:32:53 +00:00
/*
* The matching stack, we should not have to initialize this,
* since it is global but some compilers are just too braindamaged...
1995-03-24 03:32:53 +00:00
*/
struct matchstack match[MATCHSTACKSIZE] = { FALSE };
1995-03-24 03:32:53 +00:00
int top = 0;
#define push \
if (top > MATCHSTACKSIZE) \
1995-04-12 23:31:39 +00:00
yyerror("matching stack overflow"); \
else { \
match[top].user = -1; \
match[top].cmnd = -1; \
match[top].host = -1; \
match[top].runas = -1; \
match[top].nopass = -1; \
1995-03-24 03:32:53 +00:00
top++; \
}
#define pop \
if (top == 0) \
1995-04-12 23:31:39 +00:00
yyerror("matching stack underflow"); \
1995-03-24 03:32:53 +00:00
else \
top--;
1996-08-09 22:07:51 +00:00
/*
* The stack for printmatches. A list of allowed commands for the user.
* Space for cmndstack is malloc'd in parse.c
*/
struct sudo_match *matches;
int nummatches;
#define cmndpush \
if (nummatches++ > MATCHSTACKSIZE) \
yyerror("cmnd stack overflow"); \
else { \
matches[nummatches].runas = matches[nummatches].cmnd = NULL; \
matches[nummatches].nopasswd = FALSE; \
}
1995-09-01 05:03:27 +00:00
/*
* Protoypes
*/
1996-07-22 19:50:42 +00:00
extern int command_matches __P((char *, char *, char *, char *));
extern int addr_matches __P((char *));
extern int netgr_matches __P((char *, char *, char *));
extern int usergr_matches __P((char *, char *));
static int find_alias __P((char *, int));
static int add_alias __P((char *, int));
static int more_aliases __P((size_t));
void yyerror __P((char *));
1993-03-02 16:33:11 +00:00
void yyerror(s)
char *s;
1993-03-02 16:33:11 +00:00
{
/* save the line the first error occured on */
if (errorlineno == -1)
errorlineno = sudolineno;
1995-03-24 03:32:53 +00:00
#ifndef TRACELEXER
(void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s, sudolineno);
1995-03-24 03:32:53 +00:00
#else
(void) fprintf(stderr, "<*> ");
1995-03-24 03:32:53 +00:00
#endif
parse_error = TRUE;
1993-03-02 16:33:11 +00:00
}
%}
1995-03-24 03:32:53 +00:00
%union {
char *string;
int BOOLEAN;
struct sudo_command command;
1995-03-24 03:32:53 +00:00
int tok;
}
1993-03-02 16:33:11 +00:00
%start file /* special start symbol */
%token <string> ALIAS /* an UPPERCASE alias name */
%token <string> NTWKADDR /* w.x.y.z */
%token <string> FQHOST /* foo.bar.com */
%token <string> NETGROUP /* a netgroup (+NAME) */
%token <string> USERGROUP /* a usergroup (%NAME) */
%token <string> NAME /* a mixed-case name */
%token <tok> RUNAS /* a mixed-case runas name */
%token <tok> NOPASSWD /* no passwd req for command*/
%token <command> COMMAND /* an absolute pathname */
%token <tok> COMMENT /* comment and/or carriage return */
%token <tok> ALL /* ALL keyword */
%token <tok> HOSTALIAS /* Host_Alias keyword */
%token <tok> CMNDALIAS /* Cmnd_Alias keyword */
%token <tok> USERALIAS /* User_Alias keyword */
%token <tok> ':' '=' ',' '!' '.' /* union member tokens */
%token <tok> ERROR
1995-03-24 03:32:53 +00:00
%type <BOOLEAN> cmnd
%type <BOOLEAN> opcmnd
%type <BOOLEAN> runasspec
%type <BOOLEAN> runaslist
%type <BOOLEAN> runasuser
1996-07-08 17:30:39 +00:00
%type <BOOLEAN> nopasswd
1995-03-24 03:32:53 +00:00
1993-03-02 16:33:11 +00:00
%%
1995-03-24 03:32:53 +00:00
1993-03-02 16:33:11 +00:00
file : entry
| file entry
;
entry : COMMENT
{ ; }
1993-03-02 16:33:11 +00:00
| error COMMENT
{ yyerrok; }
1995-04-12 23:31:39 +00:00
| { push; } user privileges {
while (top && user_matches != TRUE) {
pop;
}
}
1995-04-09 02:27:40 +00:00
| USERALIAS useraliases
{ ; }
1995-03-24 03:32:53 +00:00
| HOSTALIAS hostaliases
{ ; }
1995-03-24 03:32:53 +00:00
| CMNDALIAS cmndaliases
{ ; }
1995-03-24 03:32:53 +00:00
;
privileges : privilege
| privileges ':' privilege
;
privilege : hostspec '=' cmndspeclist {
1995-04-12 23:31:39 +00:00
if (user_matches == TRUE) {
push;
user_matches = TRUE;
1996-07-08 17:30:39 +00:00
} else {
no_passwd = -1;
runas_matches = -1;
}
}
1995-03-24 03:32:53 +00:00
;
hostspec : ALL {
host_matches = TRUE;
}
| NTWKADDR {
1995-04-07 19:38:50 +00:00
if (addr_matches($1))
1995-03-24 03:32:53 +00:00
host_matches = TRUE;
(void) free($1);
1995-03-24 03:32:53 +00:00
}
1995-07-25 00:01:34 +00:00
| NETGROUP {
if (netgr_matches($1, host, NULL))
host_matches = TRUE;
(void) free($1);
1995-07-25 00:01:34 +00:00
}
1995-03-24 03:32:53 +00:00
| NAME {
1996-03-11 01:15:08 +00:00
if (strcasecmp(shost, $1) == 0)
1995-03-24 03:32:53 +00:00
host_matches = TRUE;
(void) free($1);
1995-03-24 03:32:53 +00:00
}
| FQHOST {
if (strcasecmp(host, $1) == 0)
1995-03-24 03:32:53 +00:00
host_matches = TRUE;
(void) free($1);
1995-03-24 03:32:53 +00:00
}
| ALIAS {
if (find_alias($1, HOST))
1995-03-24 03:32:53 +00:00
host_matches = TRUE;
(void) free($1);
1995-04-12 23:31:39 +00:00
}
1995-03-24 03:32:53 +00:00
;
cmndspeclist : cmndspec
| cmndspeclist ',' cmndspec
1995-03-24 03:32:53 +00:00
;
cmndspec : runasspec nopasswd opcmnd {
if ($1 > 0 && $3 == TRUE) {
1996-07-08 17:30:39 +00:00
runas_matches = TRUE;
if ($2 == TRUE)
no_passwd = TRUE;
1996-08-09 22:07:51 +00:00
} else if (printmatches) {
matches[nummatches].runas_len = 0;
matches[nummatches].cmnd_len = 0;
matches[nummatches].nopasswd = FALSE;
}
}
;
opcmnd : cmnd { ; }
1995-06-14 08:42:57 +00:00
| '!' {
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE) {
1996-08-09 22:07:51 +00:00
append_cmnd(&matches[nummatches], "!");
1995-06-14 08:42:57 +00:00
push;
user_matches = TRUE;
host_matches = TRUE;
} else {
push;
}
} opcmnd {
1995-03-24 03:32:53 +00:00
int cmnd_matched = cmnd_matches;
pop;
if (cmnd_matched == TRUE)
cmnd_matches = FALSE;
else if (cmnd_matched == FALSE)
cmnd_matches = TRUE;
$$ = cmnd_matches;
1995-03-24 03:32:53 +00:00
}
;
runasspec : /* empty */ {
$$ = (strcmp("root", runas_user) == 0);
}
| RUNAS runaslist {
$$ = $2;
}
;
runaslist : runasuser {
$$ = $1;
}
| runaslist ',' runasuser {
$$ = $1 + $3;
}
;
runasuser : NAME {
1996-06-20 05:17:24 +00:00
$$ = (strcmp($1, runas_user) == 0);
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE)
append_runas(&matches[nummatches], $1);
(void) free($1);
}
| USERGROUP {
1996-06-20 05:17:24 +00:00
$$ = usergr_matches($1, runas_user);
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE) {
append_runas(&matches[nummatches], "%");
append_runas(&matches[nummatches], $1);
}
(void) free($1);
}
| NETGROUP {
1996-06-20 05:17:24 +00:00
$$ = netgr_matches($1, NULL, runas_user);
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE) {
append_runas(&matches[nummatches], "+");
append_runas(&matches[nummatches], $1);
}
(void) free($1);
}
| ALIAS {
1996-06-20 05:17:24 +00:00
$$ = find_alias($1, USER);
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE)
append_runas(&matches[nummatches], $1);
(void) free($1);
}
| ALL {
1996-06-20 04:27:49 +00:00
$$ = TRUE;
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE
&& user_matches == TRUE)
append_runas(&matches[nummatches], "ALL");
}
;
1996-08-09 22:07:51 +00:00
nopasswd : /* empty */ {
$$ = FALSE;
}
1996-07-08 17:30:39 +00:00
| NOPASSWD {
$$ = TRUE;
1996-08-09 22:07:51 +00:00
if (printmatches == TRUE && host_matches == TRUE &&
user_matches == TRUE)
matches[nummatches].nopasswd = TRUE;
}
;
1995-04-09 03:11:06 +00:00
cmnd : ALL {
if (printmatches == TRUE && host_matches == TRUE &&
1996-08-09 22:07:51 +00:00
user_matches == TRUE) {
append_cmnd(&matches[nummatches], "ALL");
cmndpush;
}
1995-04-09 03:11:06 +00:00
cmnd_matches = TRUE;
$$ = TRUE;
1995-04-09 03:11:06 +00:00
}
1995-03-24 03:32:53 +00:00
| ALIAS {
if (printmatches == TRUE && host_matches == TRUE &&
1996-08-09 22:07:51 +00:00
user_matches == TRUE) {
append_cmnd(&matches[nummatches], $1);
cmndpush;
}
if (find_alias($1, CMND)) {
1995-03-24 03:32:53 +00:00
cmnd_matches = TRUE;
$$ = TRUE;
}
(void) free($1);
1995-03-24 03:32:53 +00:00
}
| COMMAND {
if (printmatches == TRUE && host_matches == TRUE &&
user_matches == TRUE) {
1996-08-09 22:07:51 +00:00
append_cmnd(&matches[nummatches], $1.cmnd);
if ($1.args) {
append_cmnd(&matches[nummatches], " ");
append_cmnd(&matches[nummatches], $1.args);
1996-07-22 19:31:04 +00:00
}
1996-08-09 22:07:51 +00:00
cmndpush;
}
/* if NewArgc > 1 pass ptr to 1st arg, else NULL */
1996-02-04 21:09:56 +00:00
if (command_matches(cmnd, (NewArgc > 1) ?
1996-07-22 19:31:04 +00:00
cmnd_args : NULL, $1.cmnd, $1.args)) {
cmnd_matches = TRUE;
$$ = TRUE;
}
(void) free($1.cmnd);
1996-08-09 22:07:51 +00:00
if ($1.args)
(void) free($1.args);
1995-03-24 03:32:53 +00:00
}
;
hostaliases : hostalias
| hostaliases ':' hostalias
;
hostalias : ALIAS { push; } '=' hostlist {
if (host_matches == TRUE && !add_alias($1, HOST))
YYERROR;
pop;
}
1993-03-02 16:33:11 +00:00
;
1995-03-24 03:32:53 +00:00
hostlist : hostspec
| hostlist ',' hostspec
1993-03-02 16:33:11 +00:00
;
1995-03-24 03:32:53 +00:00
cmndaliases : cmndalias
| cmndaliases ':' cmndalias
1993-03-02 16:33:11 +00:00
;
1995-03-24 03:32:53 +00:00
cmndalias : ALIAS { push; } '=' cmndlist {
if (cmnd_matches == TRUE && !add_alias($1, CMND))
YYERROR;
pop;
(void) free($1);
1995-03-24 03:32:53 +00:00
}
1993-03-02 16:33:11 +00:00
;
1995-03-24 03:32:53 +00:00
cmndlist : cmnd
{ ; }
1995-03-24 03:32:53 +00:00
| cmndlist ',' cmnd
1993-03-02 16:33:11 +00:00
;
1995-03-24 03:32:53 +00:00
1995-04-09 02:27:40 +00:00
useraliases : useralias
| useraliases ':' useralias
;
useralias : ALIAS { push; } '=' userlist {
1995-04-09 03:11:06 +00:00
if (user_matches == TRUE && !add_alias($1, USER))
1995-04-09 02:27:40 +00:00
YYERROR;
pop;
(void) free($1);
1995-04-09 02:27:40 +00:00
}
;
userlist : user
{ ; }
1995-04-09 02:27:40 +00:00
| userlist ',' user
;
user : NAME {
if (strcmp($1, user_name) == 0)
1995-04-09 03:11:06 +00:00
user_matches = TRUE;
(void) free($1);
}
1995-12-18 02:51:30 +00:00
| USERGROUP {
if (usergr_matches($1, user_name))
user_matches = TRUE;
(void) free($1);
}
1995-07-25 00:01:34 +00:00
| NETGROUP {
if (netgr_matches($1, NULL, user_name))
1995-07-25 00:01:34 +00:00
user_matches = TRUE;
(void) free($1);
1995-07-25 00:01:34 +00:00
}
1995-04-12 23:31:39 +00:00
| ALIAS {
if (find_alias($1, USER))
user_matches = TRUE;
(void) free($1);
1995-04-12 23:31:39 +00:00
}
| ALL {
user_matches = TRUE;
1995-04-09 02:27:40 +00:00
}
;
1993-03-02 16:33:11 +00:00
%%
1995-03-24 03:32:53 +00:00
typedef struct {
int type;
1995-04-10 19:07:54 +00:00
char name[BUFSIZ];
1995-03-24 03:32:53 +00:00
} aliasinfo;
#define MOREALIASES (32)
aliasinfo *aliases = NULL;
size_t naliases = 0;
size_t nslots = 0;
1995-03-24 03:32:53 +00:00
static int aliascmp(a1, a2)
const VOID *a1, *a2;
1995-03-24 03:32:53 +00:00
{
int r;
aliasinfo *ai1, *ai2;
ai1 = (aliasinfo *) a1;
ai2 = (aliasinfo *) a2;
r = strcmp(ai1->name, ai2->name);
if (r == 0)
r = ai1->type - ai2->type;
return(r);
}
static int add_alias(alias, type)
char *alias;
int type;
1995-03-24 03:32:53 +00:00
{
aliasinfo ai, *aip;
char s[512];
int ok;
ok = FALSE; /* assume failure */
ai.type = type;
(void) strcpy(ai.name, alias);
if (lfind((VOID *)&ai, (VOID *)aliases, &naliases, sizeof(ai),
aliascmp) != NULL) {
(void) sprintf(s, "Alias `%s' already defined", alias);
1995-03-24 03:32:53 +00:00
yyerror(s);
} else {
if (naliases == nslots && !more_aliases(nslots)) {
(void) sprintf(s, "Out of memory defining alias `%s'", alias);
yyerror(s);
}
aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases,
&naliases, sizeof(ai), aliascmp);
1995-03-24 03:32:53 +00:00
if (aip != NULL) {
ok = TRUE;
} else {
(void) sprintf(s, "Aliases corrupted defining alias `%s'", alias);
yyerror(s);
}
}
return(ok);
}
static int find_alias(alias, type)
char *alias;
int type;
1995-03-24 03:32:53 +00:00
{
aliasinfo ai;
(void) strcpy(ai.name, alias);
1995-03-24 03:32:53 +00:00
ai.type = type;
return(lfind((VOID *)&ai, (VOID *)aliases, &naliases,
1995-09-01 04:25:17 +00:00
sizeof(ai), aliascmp) != NULL);
1995-03-24 03:32:53 +00:00
}
static int more_aliases(nslots)
size_t nslots;
1995-03-24 03:32:53 +00:00
{
aliasinfo *aip;
1995-03-24 03:32:53 +00:00
if (nslots == 0)
1995-03-29 22:41:35 +00:00
aip = (aliasinfo *) malloc(MOREALIASES * sizeof(*aip));
1995-03-24 03:32:53 +00:00
else
aip = (aliasinfo *) realloc(aliases,
1995-03-29 22:41:35 +00:00
(nslots + MOREALIASES) * sizeof(*aip));
1995-03-24 03:32:53 +00:00
if (aip != NULL) {
aliases = aip;
nslots += MOREALIASES;
}
return(aip != NULL);
}
void dumpaliases()
1995-03-24 03:32:53 +00:00
{
size_t n;
1995-03-24 03:32:53 +00:00
1995-04-12 23:31:39 +00:00
for (n = 0; n < naliases; n++) {
switch (aliases[n].type) {
case HOST:
(void) puts("HOST");
1995-04-12 23:31:39 +00:00
break;
1995-03-24 03:32:53 +00:00
1995-04-12 23:31:39 +00:00
case CMND:
(void) puts("CMND");
1995-04-12 23:31:39 +00:00
break;
case USER:
(void) puts("USER");
1995-04-12 23:31:39 +00:00
break;
}
(void) printf("\t%s\n", aliases[n].name);
1995-04-12 23:31:39 +00:00
}
1995-03-24 03:32:53 +00:00
}
1996-08-09 22:07:51 +00:00
void list_matches()
{
int i;
char *p;
for (i = 0; i < nummatches; i++) {
/* Print the runas list. */
if (matches[i].runas) {
(void) putchar('(');
if ((p = strtok(matches[i].runas, ":")))
(void) fputs(p, stdout);
while ((p = strtok(NULL, ":"))) {
(void) fputs(", ", stdout);
(void) fputs(p, stdout);
}
(void) fputs(") ", stdout);
} else {
(void) fputs("(root) ", stdout);
}
/* Is a password required? */
if (matches[i].nopasswd == TRUE)
(void) fputs("NOPASSWD: ", stdout);
/* Print the actual command. */
(void) puts(matches[i].cmnd);
}
}
void reset_aliases()
{
if (aliases)
(void) free(aliases);
naliases = nslots = 0;
}
1996-08-09 22:07:51 +00:00
/* XXX - merge into one function? (note: one always adds a ':' */
static void append_runas(match, runas)
struct sudo_match *match;
char *runas;
{
size_t len = strlen(runas) + 1;
if (match->runas == NULL) {
if (!(match->runas = (char *) malloc(BUFSIZ))) {
perror("malloc");
(void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]);
exit(1);
}
/* Assumes BUFSIZ > max username length */
match->runas_size = BUFSIZ;
match->runas_len = len - 1;
(void) strcpy(match->runas, runas);
} else {
/* Allocate more space if necesary. */
while (match->runas_size <= match->runas_len + len) {
match->runas_size += BUFSIZ;
if (!(match->runas = (char *) realloc(match->runas, match->runas_size))) {
perror("malloc");
(void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]);
exit(1);
}
}
*(match->runas + match->runas_len) = ':';
(void) strcpy(match->runas + match->runas_len + 1, runas);
match->runas_len += len;
}
}
static void append_cmnd(match, cmnd)
struct sudo_match *match;
char *cmnd;
{
size_t len = strlen(cmnd);
if (match->cmnd == NULL) {
if (!(match->cmnd = (char *) malloc(BUFSIZ))) {
perror("malloc");
(void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]);
exit(1);
}
/* Assumes BUFSIZ > max username length */
match->cmnd_size = BUFSIZ;
match->cmnd_len = len;
(void) strcpy(match->cmnd, cmnd);
} else {
/* Allocate more space if necesary. */
while (match->cmnd_size <= match->cmnd_len + len) {
match->cmnd_size += BUFSIZ;
if (!(match->cmnd = (char *) realloc(match->cmnd, match->cmnd_size))) {
perror("malloc");
(void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]);
exit(1);
}
}
(void) strcpy(match->cmnd + match->cmnd_len, cmnd);
match->cmnd_len += len;
}
}