[BACK]Return to parse.lex CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

File: [local] / src / usr.bin / sudo / Attic / parse.lex (download)

Revision 1.8, Tue Jan 7 00:04:48 2003 UTC (21 years, 5 months ago) by millert
Branch: MAIN
Changes since 1.7: +9 -6 lines

Better fix for sudoers files w/o a newline before EOF.  It looks
like the issue is that yyrestart() does not reset the start condition
to INITIAL which is an issue since we parse sudoers multiple times.
This is a cleaner fix for that problem and what will go in sudo 1.6.7.

%{
/*
 * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
 * All rights reserved.
 *
 * This code is derived from software contributed by Chris Jepeway.
 *
 * This code is derived from software contributed by Chris Jepeway
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 4. Products derived from this software may not be called "Sudo" nor
 *    may "Sudo" appear in their names without specific prior written
 *    permission from the author.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
#  include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
#  include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
# include <malloc.h>
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
#include <ctype.h>
#include "sudo.h"
#include "parse.h"
#include <sudo.tab.h>

#ifndef lint
static const char rcsid[] = "$Sudo: parse.lex,v 1.119 2002/03/16 00:44:47 millert Exp $";
#endif /* lint */

#undef yywrap		/* guard against a yywrap macro */

extern YYSTYPE yylval;
extern int clearaliases;
int sudolineno = 1;
static int sawspace = 0;
static int arg_len = 0;
static int arg_size = 0;

static void fill		__P((char *, int));
static void fill_cmnd		__P((char *, int));
static void fill_args		__P((char *, int, int));
extern void reset_aliases	__P((void));
extern void yyerror		__P((char *));

/* realloc() to size + COMMANDARGINC to make room for command args */
#define COMMANDARGINC	64

#ifdef TRACELEXER
#define LEXTRACE(msg)	fputs(msg, stderr)
#else
#define LEXTRACE(msg)
#endif
%}

OCTET			(1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
DOTTEDQUAD		{OCTET}(\.{OCTET}){3}
HOSTNAME		[[:alnum:]_-]+
WORD			([^#@!=:,\(\) \t\n\\]|\\[^\n])+
ENVAR			([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
DEFVAR			[a-z_]+

/* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
%s	GOTRUNAS
%s	GOTDEFS
%x	GOTCMND
%x	STARTDEFS
%x	INDEFS

%%
<GOTDEFS>[[:blank:]]+	BEGIN STARTDEFS;

<STARTDEFS>{DEFVAR}	{
			    BEGIN INDEFS;
			    LEXTRACE("DEFVAR ");
			    fill(yytext, yyleng);
			    return(DEFVAR);
			}

<INDEFS>{
    ,			{
			    BEGIN STARTDEFS;
			    LEXTRACE(", ");
			    return(',');
			}			/* return ',' */

    =			{
			    LEXTRACE("= ");
			    return('=');
			}			/* return '=' */

    \+=			{
			    LEXTRACE("+= ");
			    return('+');
			}			/* return '+' */

    -=			{
			    LEXTRACE("-= ");
			    return('-');
			}			/* return '-' */

    \"([^\"]|\\\")+\"	{
			    LEXTRACE("WORD(1) ");
			    fill(yytext + 1, yyleng - 2);
			    return(WORD);
			}

    {ENVAR}		{
			    LEXTRACE("WORD(2) ");
			    fill(yytext, yyleng);
			    return(WORD);
			}
}

<GOTCMND>{
    \\[:\\,= \t#]	{
			    LEXTRACE("QUOTEDCHAR ");
			    fill_args(yytext + 1, 1, sawspace);
			    sawspace = FALSE;
			}

    [#:\,=\n]		{
			    BEGIN INITIAL;
			    unput(*yytext);
			    return(COMMAND);
			}			/* end of command line args */

    [^\\:, \t\n]+ 	{
			    LEXTRACE("ARG ");
			    fill_args(yytext, yyleng, sawspace);
			    sawspace = FALSE;
			}			/* a command line arg */
}

<INITIAL>^Defaults[:@]?	{
			    BEGIN GOTDEFS;
			    switch (yytext[8]) {
				case ':':
				    LEXTRACE("DEFAULTS_USER ");
				    return(DEFAULTS_USER);
				case '@':
				    LEXTRACE("DEFAULTS_HOST ");
				    return(DEFAULTS_HOST);
				default:
				    LEXTRACE("DEFAULTS ");
				    return(DEFAULTS);
			    }
			}

<INITIAL>^(Host|Cmnd|User|Runas)_Alias	{
			    fill(yytext, yyleng);
			    switch (*yytext) {
				case 'H':
				    LEXTRACE("HOSTALIAS ");
				    return(HOSTALIAS);
				case 'C':
				    LEXTRACE("CMNDALIAS ");
				    return(CMNDALIAS);
				case 'U':
				    LEXTRACE("USERALIAS ");
				    return(USERALIAS);
				case 'R':
				    LEXTRACE("RUNASALIAS ");
				    BEGIN GOTRUNAS;
				    return(RUNASALIAS);
			    }
			}

NOPASSWD[[:blank:]]*:	{
				/* cmnd does not require passwd for this user */
			    	LEXTRACE("NOPASSWD ");
			    	return(NOPASSWD);
			}

PASSWD[[:blank:]]*:	{
				/* cmnd requires passwd for this user */
			    	LEXTRACE("PASSWD ");
			    	return(PASSWD);
			}

\+{WORD}		{
			    /* netgroup */
			    fill(yytext, yyleng);
			    LEXTRACE("NETGROUP ");
			    return(NETGROUP);
			}

\%{WORD}		{
			    /* UN*X group */
			    fill(yytext, yyleng);
			    LEXTRACE("GROUP ");
			    return(USERGROUP);
			}

{DOTTEDQUAD}(\/{DOTTEDQUAD})? {
			    fill(yytext, yyleng);
			    LEXTRACE("NTWKADDR ");
			    return(NTWKADDR);
			}

{DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
			    fill(yytext, yyleng);
			    LEXTRACE("NTWKADDR ");
			    return(NTWKADDR);
			}

<INITIAL>\(		{
				BEGIN GOTRUNAS;
				LEXTRACE("RUNAS ");
				return (RUNAS);
			}

[[:upper:]][[:upper:][:digit:]_]* {
			    if (strcmp(yytext, "ALL") == 0) {
				LEXTRACE("ALL ");
				return(ALL);
			    } else {
				fill(yytext, yyleng);
				LEXTRACE("ALIAS ");
				return(ALIAS);
			    }
			}

<GOTRUNAS>(#[0-9-]+|{WORD}) {
			    /* username/uid that user can run command as */
			    fill(yytext, yyleng);
			    LEXTRACE("WORD(3) ");
			    return(WORD);
			}

<GOTRUNAS>\)		{
			    BEGIN INITIAL;
			}

\/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+	{
			    /* directories can't have args... */
			    if (yytext[yyleng - 1] == '/') {
				LEXTRACE("COMMAND ");
				fill_cmnd(yytext, yyleng);
				return(COMMAND);
			    } else {
				BEGIN GOTCMND;
				LEXTRACE("COMMAND ");
				fill_cmnd(yytext, yyleng);
			    }
			}			/* a pathname */

<INITIAL,GOTDEFS>{WORD} {
			    /* a word */
			    fill(yytext, yyleng);
			    LEXTRACE("WORD(4) ");
			    return(WORD);
			}

,			{
			    LEXTRACE(", ");
			    return(',');
			}			/* return ',' */

=			{
			    LEXTRACE("= ");
			    return('=');
			}			/* return '=' */

:			{
			    LEXTRACE(": ");
			    return(':');
			}			/* return ':' */

<*>!+			{
			    if (yyleng % 2 == 1)
				return('!');	/* return '!' */
			}

<*>\n			{
			    BEGIN INITIAL;
			    ++sudolineno;
			    LEXTRACE("\n");
			    return(COMMENT);
			}			/* return newline */

<*>[[:blank:]]+		{			/* throw away space/tabs */
			    sawspace = TRUE;	/* but remember for fill_args */
			}

<*>\\[[:blank:]]*\n	{
			    sawspace = TRUE;	/* remember for fill_args */
			    ++sudolineno;
			    LEXTRACE("\n\t");
			}			/* throw away EOL after \ */

<INITIAL,STARTDEFS,INDEFS>#.*\n	{
			    BEGIN INITIAL;
			    ++sudolineno;
			    LEXTRACE("\n");
			    return(COMMENT);
			}			/* return comments */

<*>.			{
			    LEXTRACE("ERROR ");
			    return(ERROR);
			}	/* parse error */

<*><<EOF>>		{
			    if (YY_START != INITIAL) {
			    	BEGIN INITIAL;
				LEXTRACE("ERROR ");
				return(ERROR);
			    }
			    yyterminate();
			}

%%
static void
fill(s, len)
    char *s;
    int len;
{
    int i, j;

    yylval.string = (char *) malloc(len + 1);
    if (yylval.string == NULL)
	yyerror("unable to allocate memory");

    /* Copy the string and collapse any escaped characters. */
    for (i = 0, j = 0; i < len; i++, j++) {
	if (s[i] == '\\' && i != len - 1)
	    yylval.string[j] = s[++i];
	else
	    yylval.string[j] = s[i];
    }
    yylval.string[j] = '\0';
}

static void
fill_cmnd(s, len)
    char *s;
    int len;
{
    arg_len = arg_size = 0;

    yylval.command.cmnd = (char *) malloc(len + 1);
    if (yylval.command.cmnd == NULL)
	yyerror("unable to allocate memory");

    /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
    (void) strncpy(yylval.command.cmnd, s, len);
    yylval.command.cmnd[len] = '\0';

    yylval.command.args = NULL;
}

static void
fill_args(s, len, addspace)
    char *s;
    int len;
    int addspace;
{
    int new_len;
    char *p;

    /*
     * If first arg, malloc() some room, else if we don't
     * have enough space realloc() some more.
     */
    if (yylval.command.args == NULL) {
	addspace = 0;
	new_len = len;

	while (new_len >= (arg_size += COMMANDARGINC))
	    ;

	yylval.command.args = (char *) malloc(arg_size);
	if (yylval.command.args == NULL)
	    yyerror("unable to allocate memory");
    } else {
	new_len = arg_len + len + addspace;

	if (new_len >= arg_size) {
	    /* Allocate more space than we need for subsequent args */
	    while (new_len >= (arg_size += COMMANDARGINC))
		;

	    if ((p = (char *) realloc(yylval.command.args, arg_size)) == NULL) {
		free(yylval.command.args);
		yyerror("unable to allocate memory");
	    } else
		yylval.command.args = p;
	}
    }

    /* Efficiently append the arg (with a leading space if needed). */
    p = yylval.command.args + arg_len;
    if (addspace)
	*p++ = ' ';
    (void) strcpy(p, s);
    arg_len = new_len;
}

int
yywrap()
{

    /* Free space used by the aliases unless called by testsudoers. */
    if (clearaliases)
	reset_aliases();

    return(TRUE);
}