%{
/*
- * 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
#include <config.h>
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include "toke.h"
#include <gram.h>
#include "lbuf.h"
+#include "sha2.h"
#include "secure_path.h"
-extern YYSTYPE yylval;
+extern YYSTYPE sudoerslval;
extern bool parse_error;
extern bool sudoers_warnings;
int sudolineno;
static bool continued, sawspace;
static int prev_state;
+static int digest_len;
static bool _push_include(char *, bool);
static bool pop_include(void);
static char *parse_include(char *);
-static int sudoers_trace_print(const char *msg);
int (*trace_print)(const char *msg) = sudoers_trace_print;
#define LEXRETURN(n) do { \
return (n); \
} while (0)
-#define ECHO ignore_result(fwrite(yytext, yyleng, 1, yyout))
+#define ECHO ignore_result(fwrite(sudoerstext, sudoersleng, 1, sudoersout))
#define push_include(_p) (_push_include((_p), false))
#define push_includedir(_p) (_push_include((_p), true))
%option noinput
%option nounput
%option noyywrap
+%option prefix="sudoers"
%s GOTDEFS
%x GOTCMND
%x STARTDEFS
%x INDEFS
%x INSTR
+%s WANTDIGEST
%%
<GOTDEFS>[[:blank:]]*,[[:blank:]]* {
<STARTDEFS>{DEFVAR} {
BEGIN INDEFS;
LEXTRACE("DEFVAR ");
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXRETURN(DEFVAR);
}
\" {
LEXTRACE("BEGINSTR ");
- yylval.string = NULL;
+ sudoerslval.string = NULL;
prev_state = YY_START;
BEGIN INSTR;
}
{ENVAR} {
LEXTRACE("WORD(2) ");
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXRETURN(WORD);
}
LEXTRACE("ENDSTR ");
BEGIN prev_state;
- if (yylval.string == NULL) {
+ if (sudoerslval.string == NULL) {
LEXTRACE("ERROR "); /* empty string */
LEXRETURN(ERROR);
}
if (prev_state == INITIAL) {
- switch (yylval.string[0]) {
+ switch (sudoerslval.string[0]) {
case '%':
- if (yylval.string[1] == '\0' ||
- (yylval.string[1] == ':' &&
- yylval.string[2] == '\0')) {
+ if (sudoerslval.string[1] == '\0' ||
+ (sudoerslval.string[1] == ':' &&
+ sudoerslval.string[2] == '\0')) {
LEXTRACE("ERROR "); /* empty group */
LEXRETURN(ERROR);
}
LEXTRACE("USERGROUP ");
LEXRETURN(USERGROUP);
case '+':
- if (yylval.string[1] == '\0') {
+ if (sudoerslval.string[1] == '\0') {
LEXTRACE("ERROR "); /* empty netgroup */
LEXRETURN(ERROR);
}
\\ {
LEXTRACE("BACKSLASH ");
- if (!append(yytext, yyleng))
+ if (!append(sudoerstext, sudoersleng))
yyterminate();
}
([^\"\n\\]|\\\")+ {
LEXTRACE("STRBODY ");
- if (!append(yytext, yyleng))
+ if (!append(sudoerstext, sudoersleng))
yyterminate();
}
}
\\[\*\?\[\]\!] {
/* quoted fnmatch glob char, pass verbatim */
LEXTRACE("QUOTEDCHAR ");
- if (!fill_args(yytext, 2, sawspace))
+ if (!fill_args(sudoerstext, 2, sawspace))
yyterminate();
sawspace = false;
}
\\[:\\,= \t#] {
/* quoted sudoers special char, strip backslash */
LEXTRACE("QUOTEDCHAR ");
- if (!fill_args(yytext + 1, 1, sawspace))
+ if (!fill_args(sudoerstext + 1, 1, sawspace))
yyterminate();
sawspace = false;
}
[^#\\:, \t\n]+ {
LEXTRACE("ARG ");
- if (!fill_args(yytext, yyleng, sawspace))
+ if (!fill_args(sudoerstext, sudoersleng, sawspace))
yyterminate();
sawspace = false;
} /* a command line arg */
}
+<WANTDIGEST>[[:xdigit:]]+ {
+ /* Only return DIGEST if the length is correct. */
+ if (sudoersleng == digest_len * 2) {
+ if (!fill(sudoerstext, sudoersleng))
+ yyterminate();
+ BEGIN INITIAL;
+ LEXTRACE("DIGEST ");
+ LEXRETURN(DIGEST);
+ }
+ BEGIN INITIAL;
+ yyless(sudoersleng);
+ } /* hex digest */
+
+<WANTDIGEST>[A-Za-z0-9\+/=]+ {
+ /* Only return DIGEST if the length is correct. */
+ size_t len;
+ if (sudoerstext[sudoersleng - 1] == '=') {
+ /* use padding */
+ len = 4 * ((digest_len + 2) / 3);
+ } else {
+ /* no padding */
+ len = (4 * digest_len + 2) / 3;
+ }
+ if (sudoersleng == len) {
+ if (!fill(sudoerstext, sudoersleng))
+ yyterminate();
+ BEGIN INITIAL;
+ LEXTRACE("DIGEST ");
+ LEXRETURN(DIGEST);
+ }
+ BEGIN INITIAL;
+ yyless(sudoersleng);
+ } /* base64 digest */
+
<INITIAL>^#include[[:blank:]]+.*\n {
char *path;
LEXRETURN(ERROR);
}
- if ((path = parse_include(yytext)) == NULL)
+ if ((path = parse_include(sudoerstext)) == NULL)
yyterminate();
LEXTRACE("INCLUDE\n");
LEXRETURN(ERROR);
}
- if ((path = parse_include(yytext)) == NULL)
+ if ((path = parse_include(sudoerstext)) == NULL)
yyterminate();
LEXTRACE("INCLUDEDIR\n");
LEXRETURN(ERROR);
}
- for (n = 0; isblank((unsigned char)yytext[n]); n++)
+ for (n = 0; isblank((unsigned char)sudoerstext[n]); n++)
continue;
n += sizeof("Defaults") - 1;
- if ((deftype = yytext[n++]) != '\0') {
- while (isblank((unsigned char)yytext[n]))
+ if ((deftype = sudoerstext[n++]) != '\0') {
+ while (isblank((unsigned char)sudoerstext[n]))
n++;
}
BEGIN GOTDEFS;
LEXRETURN(ERROR);
}
- for (n = 0; isblank((unsigned char)yytext[n]); n++)
+ for (n = 0; isblank((unsigned char)sudoerstext[n]); n++)
continue;
- switch (yytext[n]) {
+ switch (sudoerstext[n]) {
case 'H':
LEXTRACE("HOSTALIAS ");
LEXRETURN(HOSTALIAS);
\+{WORD} {
/* netgroup */
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("NETGROUP ");
LEXRETURN(NETGROUP);
\%:?({WORD}|{ID}) {
/* group */
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("USERGROUP ");
LEXRETURN(USERGROUP);
}
{IPV4ADDR}(\/{IPV4ADDR})? {
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("NTWKADDR ");
LEXRETURN(NTWKADDR);
}
{IPV4ADDR}\/([12]?[0-9]|3[0-2]) {
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("NTWKADDR ");
LEXRETURN(NTWKADDR);
}
{IPV6ADDR}(\/{IPV6ADDR})? {
- if (!ipv6_valid(yytext)) {
+ if (!ipv6_valid(sudoerstext)) {
LEXTRACE("ERROR ");
LEXRETURN(ERROR);
}
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("NTWKADDR ");
LEXRETURN(NTWKADDR);
}
{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
- if (!ipv6_valid(yytext)) {
+ if (!ipv6_valid(sudoerstext)) {
LEXTRACE("ERROR ");
LEXRETURN(ERROR);
}
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("NTWKADDR ");
LEXRETURN(NTWKADDR);
goto got_alias;
#endif
}
+<INITIAL>PRIVS {
+#ifdef HAVE_PRIV_SET
+ LEXTRACE("PRIVS ");
+ LEXRETURN(PRIVS);
+#else
+ goto got_alias;
+#endif
+ }
+
+<INITIAL>LIMITPRIVS {
+#ifdef HAVE_PRIV_SET
+ LEXTRACE("LIMITPRIVS ");
+ LEXRETURN(LIMITPRIVS);
+#else
+ goto got_alias;
+#endif
+ }
[[:upper:]][[:upper:][:digit:]_]* {
-#ifndef HAVE_SELINUX
got_alias:
-#endif
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("ALIAS ");
LEXRETURN(ALIAS);
}
<GOTDEFS>({PATH}|sudoedit) {
+ /* XXX - no way to specify digest for command */
/* no command args allowed for Defaults!/path */
- if (!fill_cmnd(yytext, yyleng))
+ if (!fill_cmnd(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("COMMAND ");
LEXRETURN(COMMAND);
}
+sha224 {
+ digest_len = SHA224_DIGEST_LENGTH;
+ BEGIN WANTDIGEST;
+ LEXTRACE("SHA224 ");
+ LEXRETURN(SHA224);
+ }
+
+sha256 {
+ digest_len = SHA256_DIGEST_LENGTH;
+ BEGIN WANTDIGEST;
+ LEXTRACE("SHA256 ");
+ LEXRETURN(SHA256);
+ }
+
+sha384 {
+ digest_len = SHA384_DIGEST_LENGTH;
+ BEGIN WANTDIGEST;
+ LEXTRACE("SHA384 ");
+ LEXRETURN(SHA384);
+ }
+
+sha512 {
+ digest_len = SHA512_DIGEST_LENGTH;
+ BEGIN WANTDIGEST;
+ LEXTRACE("SHA512 ");
+ LEXRETURN(SHA512);
+ }
+
sudoedit {
BEGIN GOTCMND;
LEXTRACE("COMMAND ");
- if (!fill_cmnd(yytext, yyleng))
+ if (!fill_cmnd(sudoerstext, sudoersleng))
yyterminate();
} /* sudo -e */
{PATH} {
/* directories can't have args... */
- if (yytext[yyleng - 1] == '/') {
+ if (sudoerstext[sudoersleng - 1] == '/') {
LEXTRACE("COMMAND ");
- if (!fill_cmnd(yytext, yyleng))
+ if (!fill_cmnd(sudoerstext, sudoersleng))
yyterminate();
LEXRETURN(COMMAND);
} else {
BEGIN GOTCMND;
LEXTRACE("COMMAND ");
- if (!fill_cmnd(yytext, yyleng))
+ if (!fill_cmnd(sudoerstext, sudoersleng))
yyterminate();
}
} /* a pathname */
<INITIAL,GOTDEFS>\" {
LEXTRACE("BEGINSTR ");
- yylval.string = NULL;
+ sudoerslval.string = NULL;
prev_state = YY_START;
BEGIN INSTR;
}
<INITIAL,GOTDEFS>({ID}|{WORD}) {
/* a word */
- if (!fill(yytext, yyleng))
+ if (!fill(sudoerstext, sudoersleng))
yyterminate();
LEXTRACE("WORD(5) ");
LEXRETURN(WORD);
} /* return ':' */
<*>!+ {
- if (yyleng & 1) {
+ if (sudoersleng & 1) {
LEXTRACE("!");
LEXRETURN('!'); /* return '!' */
}
if (!(dir = opendir(dirpath))) {
if (errno != ENOENT) {
- char *errbuf;
- if (asprintf(&errbuf, _("%s: %s"), dirpath, strerror(errno)) != -1) {
- yyerror(errbuf);
- free(errbuf);
- } else {
- yyerror(_("unable to allocate memory"));
- }
+ warning("%s", dirpath);
+ sudoerserror(NULL);
}
goto done;
}
pl->path = path;
pl->next = first;
first = pl;
+ path = NULL;
count++;
}
closedir(dir);
while (first != NULL) {
pl = first;
first = pl->next;
- free(pl->path);
- free(pl);
+ efree(pl->path);
+ efree(pl);
}
efree(sorted);
efree(dirpath);
efree(istack[idepth].path);
if (idepth && !istack[idepth].keepopen)
fclose(istack[idepth].bs->yy_input_file);
- yy_delete_buffer(istack[idepth].bs);
+ sudoers_delete_buffer(istack[idepth].bs);
}
efree(istack);
istack = NULL;
/* push current state onto stack */
if (idepth >= istacksize) {
if (idepth > MAX_SUDOERS_DEPTH) {
- yyerror(_("too many levels of includes"));
+ sudoerserror(N_("too many levels of includes"));
debug_return_bool(false);
}
istacksize += SUDOERS_STACK_INCREMENT;
istack = (struct include_stack *) realloc(istack,
sizeof(*istack) * istacksize);
if (istack == NULL) {
- yyerror(_("unable to allocate memory"));
+ warning(NULL);
+ sudoerserror(NULL);
debug_return_bool(false);
}
}
if (isdir) {
struct stat sb;
switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) {
+ case SUDO_PATH_SECURE:
+ break;
case SUDO_PATH_MISSING:
debug_return_bool(false);
case SUDO_PATH_BAD_TYPE:
debug_return_bool(false);
}
if (!(path = switch_dir(&istack[idepth], path))) {
- /* switch_dir() called yyerror() for us */
+ /* switch_dir() called sudoerserror() for us */
debug_return_bool(false);
}
while ((fp = open_sudoers(path, false, &keepopen)) == NULL) {
}
} else {
if ((fp = open_sudoers(path, true, &keepopen)) == NULL) {
- char *errbuf;
- if (asprintf(&errbuf, _("%s: %s"), path, strerror(errno)) != -1) {
- yyerror(errbuf);
- free(errbuf);
- } else {
- yyerror(_("unable to allocate memory"));
- }
+ /* The error was already printed by open_sudoers() */
+ sudoerserror(NULL);
debug_return_bool(false);
}
istack[idepth].more = NULL;
idepth++;
sudolineno = 1;
sudoers = path;
- yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+ sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE));
debug_return_bool(true);
}
if (!keepopen)
fclose(YY_CURRENT_BUFFER->yy_input_file);
- yy_delete_buffer(YY_CURRENT_BUFFER);
+ sudoers_delete_buffer(YY_CURRENT_BUFFER);
/* If we are in an include dir, move to the next file. */
while ((pl = istack[idepth - 1].more) != NULL) {
fp = open_sudoers(pl->path, false, &keepopen);
efree(sudoers);
sudoers = pl->path;
sudolineno = 1;
- yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+ sudoers_switch_to_buffer(sudoers_create_buffer(fp, YY_BUF_SIZE));
efree(pl);
break;
}
/* If no path list, just pop the last dir on the stack. */
if (pl == NULL) {
idepth--;
- yy_switch_to_buffer(istack[idepth].bs);
+ sudoers_switch_to_buffer(istack[idepth].bs);
efree(sudoers);
sudoers = istack[idepth].path;
sudolineno = istack[idepth].lineno;
len += (int)(ep - cp);
path = pp = malloc(len + dirlen + 1);
if (path == NULL) {
- yyerror(_("unable to allocate memory"));
+ warning(NULL);
+ sudoerserror(NULL);
debug_return_str(NULL);
}
if (dirlen) {
}
#ifdef TRACELEXER
-static int
+int
sudoers_trace_print(const char *msg)
{
return fputs(msg, stderr);
}
#else
-static int
+int
sudoers_trace_print(const char *msg)
{
static bool initialized;