/* * Copyright (C)1996-1997,1999 Ian Jackson * * This 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 2 of the License, 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 userv; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "both.h" #include "tokens.h" #define HYPHEN '-' typedef int directive_fnt(int dtoken); static directive_fnt df_reject, df_execute, df_executefrompath; static directive_fnt df_executefromdirectory, df_executebuiltin; static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile; static directive_fnt dfg_fdwant, dfg_setflag; static directive_fnt df_reset, df_cd, df_userrcfile, df_include; static directive_fnt df_includelookup, df_includedirectory; static directive_fnt df_message, df_error, df_quit, df_eof; static directive_fnt df_if, df_catchquit, df_errorspush; static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig; /* directive functions return: * 0 for success having scanned up to and including end of line but not beyond, * or tokv_error or tokv_quit. * They expect to parse the whitespace before their parameters (if any). */ typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue); static parmcondition_fnt pcf_glob, pcf_range, pcf_grep; /* all conditional functions return tokv_error for failure or 0 for success * at parsing and testing, in which case *rtrue is set to 0 or 1. * On success they have scanned up to and including the condition's * terminating newline; the pcf_... functions expect to parse the whitespace * between the parameter name and the condition's arguments. * Otherwise they return tokv_error. * The parameter-based conditionals take a list of parameter values * as obtained from the parameter functions and pa_parameter, * and do _not_ free it. */ typedef int parameter_fnt(int ptoken, char ***rvalues); static parameter_fnt pf_service; static parameter_fnt pf_callinguser, pf_serviceuser; static parameter_fnt pf_callinggroup, pf_servicegroup; static parameter_fnt pf_callingusershell, pf_serviceusershell; /* Parameter functions return tokv_error or 0 for success at parsing * and determining the value, in which case *rvalues is made to be * a mallocd null-terminated array of pointers to mallocd strings. * freeparm can be used to free such an array. */ typedef int builtinserviceparse_fnt(char ***rnewargs); static builtinserviceparse_fnt bispa_none, bispa_parameter; /* These parse the arguments to a builtin service, including the * newline at the end of the line. *rnewargs will initially be * null, indicating that no arguments are to be set; the function * may store a mallocd array of mallocd strings in it, * containing the arguments it wishes to have set (null-pointer * terminated). */ static int yylex(void); /* Returns a token (which may be an eof or error exception) */ static directive_fnt *lr_dir; static parmcondition_fnt *lr_parmcond; static builtinserviceparse_fnt *lr_bispa; static builtinserviceexec_fnt *lr_bisexec; static parameter_fnt *lr_parameter; static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; static int lr_flagval, lr_controlend; static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */ /* Forward declarations of things used in lexer and parser */ struct parser_state { int lineno, reportlineno, notedreferer, isinternal; const char *filename; struct stat filestab; YY_BUFFER_STATE ybuf; struct parser_state *upstate; }; static struct parser_state *cstate; struct error_handling { int handling; /* One of the error handling modes tokt_ehandlemode */ int logfacility, loglevel; int filekeep; /* File is in use by higher-level errors-push, leave it open */ FILE *file; char *filename; }; static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 }; static int dequote(char *inplace); static void countnewlines(void); #define YY_NO_UNPUT %} %option noyywrap %% reject { lr_dir= df_reject; return tokv_word_reject; } execute-from-directory { lr_dir= df_executefromdirectory; return tokv_word_executefromdirectory; } execute-from-path { lr_dir= df_executefrompath; return tokv_word_executefrompath; } execute-builtin { lr_dir= df_executebuiltin; return tokv_word_executebuiltin; } errors-to-stderr { lr_dir= df_errorstostderr; return tokv_word_errorstostderr; } errors-to-syslog { lr_dir= df_errorstosyslog; return tokv_word_errorstosyslog; } errors-to-file { lr_dir= df_errorstofile; return tokv_word_errorstofile; } require-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=1; return tokv_word_requirefd; } allow-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_allowfd; } null-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_nullfd; } reject-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_rejectfd; } ignore-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_ignorefd; } set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 1; return tokv_word_setenvironment; } no-set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 0; return tokv_word_nosetenvironment; } suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 1; return tokv_word_suppressargs; } no-suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 0; return tokv_word_nosuppressargs; } disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 1; return tokv_word_disconnecthup; } no-disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 0; return tokv_word_nodisconnecthup; } cd { lr_dir= df_cd; return tokv_word_cd; } user-rcfile { lr_dir= df_userrcfile; return tokv_word_userrcfile; } include { lr_dir= df_include; return tokv_word_include; } include-ifexist { lr_dir= df_include; return tokv_word_includeifexist; } include-lookup { lr_dir= df_includelookup; return tokv_word_includelookup; } include-lookup-all { lr_dir= df_includelookup; return tokv_word_includelookupall; } include-directory { lr_dir= df_includedirectory; return tokv_word_includedirectory; } message { lr_dir= df_message; return tokv_word_message; } _include-sysconfig { lr_dir= df_include; return tokv_word_includesysconfig; } _include-user-rcfile { lr_dir= dfi_includeuserrcfile; return tokv_word_includeuserrcfile; } _include-client-config { lr_dir= dfi_includeclientconfig; return tokv_word_includeclientconfig; } quit { lr_dir= df_quit; return tokv_word_quit; } eof { lr_dir= df_eof; return tokv_word_eof; } if { lr_dir= df_if; return tokv_word_if; } catch-quit { lr_dir= df_catchquit; return tokv_word_catchquit; } errors-push { lr_dir= df_errorspush; return tokv_word_errorspush; } elif { lr_controlend= tokv_word_if; return tokv_word_elif; } else { lr_controlend= tokv_word_if; return tokv_word_else; } fi { lr_controlend= tokv_word_if; return tokv_word_fi; } hctac { lr_controlend= tokv_word_catchquit; return tokv_word_hctac; } srorre { lr_controlend= tokv_word_errorspush; return tokv_word_srorre; } glob { lr_parmcond= pcf_glob; return tokv_word_glob; } range { lr_parmcond= pcf_range; return tokv_word_range; } grep { lr_parmcond= pcf_grep; return tokv_word_grep; } environment { lr_bispa= bispa_none; lr_bisexec= bisexec_environment; return tokv_word_environment; } parameter { lr_bispa= bispa_parameter; lr_bisexec= bisexec_parameter; return tokv_word_parameter; } version { lr_bispa= bispa_none; lr_bisexec= bisexec_version; return tokv_word_version; } toplevel { lr_bispa= bispa_none; lr_bisexec= bisexec_toplevel; return tokv_word_toplevel; } override { lr_bispa= bispa_none; lr_bisexec= bisexec_override; return tokv_word_override; } shutdown { lr_bispa= bispa_none; lr_bisexec= bisexec_shutdown; return tokv_word_shutdown; } reset { lr_bispa= bispa_none; lr_bisexec= bisexec_reset; lr_dir= df_reset; return tokv_word_reset; } execute { lr_bispa= bispa_none; lr_bisexec= bisexec_execute; lr_dir= df_execute; return tokv_word_execute; } help { lr_bispa= bispa_none; lr_bisexec= bisexec_help; return tokv_word_help; } service { lr_parameter= pf_service; return tokv_word_service; } calling-user { lr_parameter= pf_callinguser; return tokv_word_callinguser; } calling-group { lr_parameter= pf_callinggroup; return tokv_word_callinggroup; } calling-user-shell { lr_parameter= pf_callingusershell; return tokv_word_callingusershell; } service-user { lr_parameter= pf_serviceuser; return tokv_word_serviceuser; } service-group { lr_parameter= pf_servicegroup; return tokv_word_servicegroup; } service-user-shell { lr_parameter= pf_serviceusershell; return tokv_word_serviceusershell; } debug { lr_loglevel= LOG_DEBUG; return tokv_syslog_debug; } info { lr_loglevel= LOG_INFO; return tokv_syslog_info; } notice { lr_loglevel= LOG_NOTICE; return tokv_syslog_notice; } warn(ing)? { lr_loglevel= LOG_WARNING; return tokv_syslog_warning; } err { lr_loglevel= LOG_ERR; return tokv_syslog_err; } crit { lr_loglevel= LOG_CRIT; return tokv_syslog_crit; } alert { lr_loglevel= LOG_ALERT; return tokv_syslog_alert; } emerg|panic { lr_loglevel= LOG_EMERG; return tokv_syslog_emerg; } auth(priv)?|security { lr_logfacility= LOG_AUTHPRIV; return tokv_syslog_authpriv; } cron { lr_logfacility= LOG_CRON; return tokv_syslog_cron; } daemon { lr_logfacility= LOG_DAEMON; return tokv_syslog_daemon; } kern(el)? { lr_logfacility= LOG_KERN; return tokv_syslog_kern; } lpr { lr_logfacility= LOG_LPR; return tokv_syslog_lpr; } mail { lr_logfacility= LOG_MAIL; return tokv_syslog_mail; } news { lr_logfacility= LOG_NEWS; return tokv_syslog_news; } syslog { lr_logfacility= LOG_SYSLOG; return tokv_syslog_syslog; } user { lr_logfacility= LOG_USER; return tokv_syslog_user; } uucp { lr_logfacility= LOG_UUCP; return tokv_syslog_uucp; } local0 { lr_logfacility= LOG_LOCAL0; return tokv_syslog_local0; } local1 { lr_logfacility= LOG_LOCAL1; return tokv_syslog_local1; } local2 { lr_logfacility= LOG_LOCAL2; return tokv_syslog_local2; } local3 { lr_logfacility= LOG_LOCAL3; return tokv_syslog_local3; } local4 { lr_logfacility= LOG_LOCAL4; return tokv_syslog_local4; } local5 { lr_logfacility= LOG_LOCAL5; return tokv_syslog_local5; } local6 { lr_logfacility= LOG_LOCAL6; return tokv_syslog_local6; } local7 { lr_logfacility= LOG_LOCAL7; return tokv_syslog_local7; } read { return tokv_word_read; } write { return tokv_word_write; } \$ { return tokv_dollar; } \( { return tokv_openparen; } \) { return tokv_closeparen; } \! { return tokv_not; } \& { return tokv_and; } \| { return tokv_or; } error { lr_dir= df_error; lr_loglevel= LOG_ERR; return tokv_word_error; } [0-9]{1,8} { char *ep; lr_min=lr_max= (int)strtoul(yytext,&ep,10); assert(!*ep); return tokv_ordinal; } [0-9]{1,8}-[0-9]{1,8} { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); assert(*++ep); lr_max= (int)strtoul(ep,&ep,10); assert(!*ep); if (lr_max < lr_min) return parseerrprint("fd range has min > max"); return tokv_fdrange; } [0-9]{1,8}- { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); assert(!*++ep); lr_max=-1; return tokv_fdstoend; } ([\ \t]*\\[\ \t]*\n[\ \t]*)+ countnewlines(); return tokv_lwsp; [\ \t]+ return tokv_lwsp; [\ \t]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]* return parseerrprint("missing newline at eof after comment"); \"([^\\\"\n]|\\[a-z]|\\[0-9]{3}|\\x[0-9A-Fa-f]{2}|\\[[:punct:]]|\\[ \t]*\n)*\" { countnewlines(); return dequote(yytext); } [^\ \t\n\\\"]+ return tokv_barestring; <> return tokv_eof; \" return parseerrprint("misquoted or unterminated string"); \\ return parseerrprint("unexpected backslash"); . abort(); /* expect lex warning "rule cannot be matched" */ %% const char *const builtinservicehelpstrings[]= { "environment", "parameter ", "version", "toplevel", "override", "shutdown", "reset", "execute", "help", 0 }; #include "parser.c"