1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
/*
* userv is copyright Ian Jackson and other contributors.
* See README for full authorship information.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
%{
#include <syslog.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <fnmatch.h>
#include <limits.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#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, dfg_lookupquotemode;
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_INPUT
%}
%option noyywrap
%option nounput
%%
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; }
include-lookup-quote-old { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquoteold; }
include-lookup-quote-new { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquotenew; }
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; }
stdin { lr_max= lr_min= 0; return tokv_word_stdin; }
stdout { lr_max= lr_min= 1; return tokv_word_stdout; }
stderr { lr_max= lr_min= 2; return tokv_word_stderr; }
\( { 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);
ep++; 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);
ep++; 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;
<<EOF>> 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 <parameter>",
"version",
"toplevel",
"override",
"shutdown",
"reset",
"execute",
"help",
0
};
#include "parser.c"
|