chiark / gitweb /
3dc8590ac6009ed9518ddf141ceeed611ae79aa6
[userv.git] / lexer.l
1 /*
2  *   Copyright (C)1996-1997,1999 Ian Jackson
3  *  
4  *   This is free software; you can redistribute it and/or modify it
5  *   under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *  
9  *   This program is distributed in the hope that it will be useful, but
10  *   WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *   General Public License for more details.
13  *  
14  *   You should have received a copy of the GNU General Public License
15  *   along with userv; if not, write to the Free Software
16  *   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 %{
20
21
22
23
24
25 #include <syslog.h>
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <fnmatch.h>
35 #include <limits.h>
36 #include <dirent.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <time.h>
40 #include <errno.h>
41
42 #include "config.h"
43 #include "common.h"
44 #include "daemon.h"
45 #include "lib.h"
46 #include "both.h"
47 #include "tokens.h"
48
49 #define HYPHEN '-'
50
51 typedef int directive_fnt(int dtoken);
52 static directive_fnt df_reject, df_execute, df_executefrompath;
53 static directive_fnt df_executefromdirectory, df_executebuiltin;
54 static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile;
55 static directive_fnt dfg_fdwant, dfg_setflag, dfg_lookupquotemode;
56 static directive_fnt df_reset, df_cd, df_userrcfile, df_include;
57 static directive_fnt df_includelookup, df_includedirectory;
58 static directive_fnt df_message, df_error, df_quit, df_eof;
59 static directive_fnt df_if, df_catchquit, df_errorspush;
60 static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig;
61 /* directive functions return:
62  *  0 for success having scanned up to and including end of line but not beyond,
63  *  or tokv_error or tokv_quit.
64  * They expect to parse the whitespace before their parameters (if any).
65  */
66
67 typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue);
68 static parmcondition_fnt pcf_glob, pcf_range, pcf_grep;
69 /* all conditional functions return tokv_error for failure or 0 for success
70  *  at parsing and testing, in which case *rtrue is set to 0 or 1.
71  *  On success they have scanned up to and including the condition's
72  *  terminating newline; the pcf_... functions expect to parse the whitespace
73  *  between the parameter name and the condition's arguments.
74  * Otherwise they return tokv_error.
75  * The parameter-based conditionals take a list of parameter values
76  * as obtained from the parameter functions and pa_parameter,
77  * and do _not_ free it.
78  */
79
80 typedef int parameter_fnt(int ptoken, char ***rvalues);
81 static parameter_fnt pf_service;
82 static parameter_fnt pf_callinguser, pf_serviceuser;
83 static parameter_fnt pf_callinggroup, pf_servicegroup;
84 static parameter_fnt pf_callingusershell, pf_serviceusershell;
85 /* Parameter functions return tokv_error or 0 for success at parsing
86  * and determining the value, in which case *rvalues is made to be
87  * a mallocd null-terminated array of pointers to mallocd strings.
88  * freeparm can be used to free such an array.
89  */
90
91 typedef int builtinserviceparse_fnt(char ***rnewargs);
92 static builtinserviceparse_fnt bispa_none, bispa_parameter;
93 /* These parse the arguments to a builtin service, including the
94  * newline at the end of the line.  *rnewargs will initially be
95  * null, indicating that no arguments are to be set; the function
96  * may store a mallocd array of mallocd strings in it,
97  * containing the arguments it wishes to have set (null-pointer
98  * terminated).
99  */
100
101 static int yylex(void);
102 /* Returns a token (which may be an eof or error exception) */
103
104 static directive_fnt *lr_dir;
105 static parmcondition_fnt *lr_parmcond;
106 static builtinserviceparse_fnt *lr_bispa;
107 static builtinserviceexec_fnt *lr_bisexec;
108 static parameter_fnt *lr_parameter;
109 static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag;
110 static int lr_flagval, lr_controlend;
111 static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */
112
113 /* Forward declarations of things used in lexer and parser */
114
115 struct parser_state {
116   int lineno, reportlineno, notedreferer, isinternal;
117   const char *filename;
118   struct stat filestab;
119   YY_BUFFER_STATE ybuf;
120   struct parser_state *upstate;
121 };
122
123 static struct parser_state *cstate;
124
125 struct error_handling {
126   int handling; /* One of the error handling modes tokt_ehandlemode */
127   int logfacility, loglevel;
128   int filekeep; /* File is in use by higher-level errors-push, leave it open */
129   FILE *file;
130   char *filename;
131 };
132
133 static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 };
134
135 static int dequote(char *inplace);
136 static void countnewlines(void);
137
138 #define YY_NO_INPUT
139
140 %}
141
142 %option noyywrap
143 %option nounput
144
145 %%
146
147 reject { lr_dir= df_reject; return tokv_word_reject; }
148 execute-from-directory { lr_dir= df_executefromdirectory; return tokv_word_executefromdirectory; }
149 execute-from-path { lr_dir= df_executefrompath; return tokv_word_executefrompath; }
150 execute-builtin { lr_dir= df_executebuiltin; return tokv_word_executebuiltin; }
151 errors-to-stderr { lr_dir= df_errorstostderr; return tokv_word_errorstostderr; }
152 errors-to-syslog { lr_dir= df_errorstosyslog; return tokv_word_errorstosyslog; }
153 errors-to-file { lr_dir= df_errorstofile; return tokv_word_errorstofile; }
154 include-lookup-quote-old { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquoteold; }
155 include-lookup-quote-new { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquotenew; }
156 require-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=1; return tokv_word_requirefd; }
157 allow-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_allowfd; }
158 null-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_nullfd; }
159 reject-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_rejectfd; }
160 ignore-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_ignorefd; }
161 set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 1; return tokv_word_setenvironment; }
162 no-set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 0; return tokv_word_nosetenvironment; }
163 suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 1; return tokv_word_suppressargs; }
164 no-suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 0; return tokv_word_nosuppressargs; }
165 disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 1; return tokv_word_disconnecthup; }
166 no-disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 0; return tokv_word_nodisconnecthup; }
167 cd { lr_dir= df_cd; return tokv_word_cd; }
168 user-rcfile { lr_dir= df_userrcfile; return tokv_word_userrcfile; }
169 include { lr_dir= df_include; return tokv_word_include; }
170 include-ifexist { lr_dir= df_include; return tokv_word_includeifexist; }
171 include-lookup { lr_dir= df_includelookup; return tokv_word_includelookup; }
172 include-lookup-all { lr_dir= df_includelookup; return tokv_word_includelookupall; }
173 include-directory { lr_dir= df_includedirectory; return tokv_word_includedirectory; }
174 message { lr_dir= df_message; return tokv_word_message; }
175 _include-sysconfig { lr_dir= df_include; return tokv_word_includesysconfig; }
176 _include-user-rcfile { lr_dir= dfi_includeuserrcfile; return tokv_word_includeuserrcfile; }
177 _include-client-config { lr_dir= dfi_includeclientconfig; return tokv_word_includeclientconfig; }
178 quit { lr_dir= df_quit; return tokv_word_quit; }
179 eof { lr_dir= df_eof; return tokv_word_eof; }
180 if { lr_dir= df_if; return tokv_word_if; }
181 catch-quit { lr_dir= df_catchquit; return tokv_word_catchquit; }
182 errors-push { lr_dir= df_errorspush; return tokv_word_errorspush; }
183 elif { lr_controlend= tokv_word_if; return tokv_word_elif; }
184 else { lr_controlend= tokv_word_if; return tokv_word_else; }
185 fi { lr_controlend= tokv_word_if; return tokv_word_fi; }
186 hctac { lr_controlend= tokv_word_catchquit; return tokv_word_hctac; }
187 srorre { lr_controlend= tokv_word_errorspush; return tokv_word_srorre; }
188 glob { lr_parmcond= pcf_glob; return tokv_word_glob; }
189 range { lr_parmcond= pcf_range; return tokv_word_range; }
190 grep { lr_parmcond= pcf_grep; return tokv_word_grep; }
191 environment { lr_bispa= bispa_none; lr_bisexec= bisexec_environment; return tokv_word_environment; }
192 parameter { lr_bispa= bispa_parameter; lr_bisexec= bisexec_parameter; return tokv_word_parameter; }
193 version { lr_bispa= bispa_none; lr_bisexec= bisexec_version; return tokv_word_version; }
194 toplevel { lr_bispa= bispa_none; lr_bisexec= bisexec_toplevel; return tokv_word_toplevel; }
195 override { lr_bispa= bispa_none; lr_bisexec= bisexec_override; return tokv_word_override; }
196 shutdown { lr_bispa= bispa_none; lr_bisexec= bisexec_shutdown; return tokv_word_shutdown; }
197 reset { lr_bispa= bispa_none; lr_bisexec= bisexec_reset; lr_dir= df_reset; return tokv_word_reset; }
198 execute { lr_bispa= bispa_none; lr_bisexec= bisexec_execute; lr_dir= df_execute; return tokv_word_execute; }
199 help { lr_bispa= bispa_none; lr_bisexec= bisexec_help; return tokv_word_help; }
200 service { lr_parameter= pf_service; return tokv_word_service; }
201 calling-user { lr_parameter= pf_callinguser; return tokv_word_callinguser; }
202 calling-group { lr_parameter= pf_callinggroup; return tokv_word_callinggroup; }
203 calling-user-shell { lr_parameter= pf_callingusershell; return tokv_word_callingusershell; }
204 service-user { lr_parameter= pf_serviceuser; return tokv_word_serviceuser; }
205 service-group { lr_parameter= pf_servicegroup; return tokv_word_servicegroup; }
206 service-user-shell { lr_parameter= pf_serviceusershell; return tokv_word_serviceusershell; }
207 debug { lr_loglevel= LOG_DEBUG; return tokv_syslog_debug; }
208 info { lr_loglevel= LOG_INFO; return tokv_syslog_info; }
209 notice { lr_loglevel= LOG_NOTICE; return tokv_syslog_notice; }
210 warn(ing)? { lr_loglevel= LOG_WARNING; return tokv_syslog_warning; }
211 err { lr_loglevel= LOG_ERR; return tokv_syslog_err; }
212 crit { lr_loglevel= LOG_CRIT; return tokv_syslog_crit; }
213 alert { lr_loglevel= LOG_ALERT; return tokv_syslog_alert; }
214 emerg|panic { lr_loglevel= LOG_EMERG; return tokv_syslog_emerg; }
215 auth(priv)?|security { lr_logfacility= LOG_AUTHPRIV; return tokv_syslog_authpriv; }
216 cron { lr_logfacility= LOG_CRON; return tokv_syslog_cron; }
217 daemon { lr_logfacility= LOG_DAEMON; return tokv_syslog_daemon; }
218 kern(el)? { lr_logfacility= LOG_KERN; return tokv_syslog_kern; }
219 lpr { lr_logfacility= LOG_LPR; return tokv_syslog_lpr; }
220 mail { lr_logfacility= LOG_MAIL; return tokv_syslog_mail; }
221 news { lr_logfacility= LOG_NEWS; return tokv_syslog_news; }
222 syslog { lr_logfacility= LOG_SYSLOG; return tokv_syslog_syslog; }
223 user { lr_logfacility= LOG_USER; return tokv_syslog_user; }
224 uucp { lr_logfacility= LOG_UUCP; return tokv_syslog_uucp; }
225 local0 { lr_logfacility= LOG_LOCAL0; return tokv_syslog_local0; }
226 local1 { lr_logfacility= LOG_LOCAL1; return tokv_syslog_local1; }
227 local2 { lr_logfacility= LOG_LOCAL2; return tokv_syslog_local2; }
228 local3 { lr_logfacility= LOG_LOCAL3; return tokv_syslog_local3; }
229 local4 { lr_logfacility= LOG_LOCAL4; return tokv_syslog_local4; }
230 local5 { lr_logfacility= LOG_LOCAL5; return tokv_syslog_local5; }
231 local6 { lr_logfacility= LOG_LOCAL6; return tokv_syslog_local6; }
232 local7 { lr_logfacility= LOG_LOCAL7; return tokv_syslog_local7; }
233 read { return tokv_word_read; }
234 write { return tokv_word_write; }
235 \$ { return tokv_dollar; }
236 stdin {  lr_max= lr_min= 0; return tokv_word_stdin; }
237 stdout {  lr_max= lr_min= 1; return tokv_word_stdout; }
238 stderr {  lr_max= lr_min= 2; return tokv_word_stderr; }
239 \( { return tokv_openparen; }
240 \) { return tokv_closeparen; }
241 \! { return tokv_not; }
242 \& { return tokv_and; }
243 \| { return tokv_or; }
244 error { lr_dir= df_error; lr_loglevel= LOG_ERR; return tokv_word_error; }
245
246
247
248 [0-9]{1,8}              {
249                           char *ep;
250                           lr_min=lr_max= (int)strtoul(yytext,&ep,10);
251                           assert(!*ep);
252                           return tokv_ordinal;
253                         }
254 [0-9]{1,8}-[0-9]{1,8}   {
255                           char *ep;
256                           lr_min= (int)strtoul(yytext,&ep,10);
257                           assert(*ep == HYPHEN);
258                           ep++;  assert(*ep);
259                           lr_max= (int)strtoul(ep,&ep,10);
260                           assert(!*ep);
261                           if (lr_max < lr_min)
262                             return parseerrprint("fd range has min > max");
263                           return tokv_fdrange;
264                         }
265 [0-9]{1,8}-             {
266                           char *ep;
267                           lr_min= (int)strtoul(yytext,&ep,10);
268                           assert(*ep == HYPHEN);
269                           ep++;  assert(!*ep);
270                           lr_max=-1;
271                           return tokv_fdstoend;
272                         }
273 ([\ \t]*\\[\ \t]*\n[\ \t]*)+    countnewlines(); return tokv_lwsp;
274 [\ \t]+                         return tokv_lwsp;
275 [\ \t]*\n               cstate->lineno++; return tokv_newline;
276 [\ \t]*\#[^\n]*\n       cstate->lineno++; return tokv_newline;
277 [\ \t]*\#[^\n]*         return parseerrprint("missing newline at eof after comment");
278 \"([^\\\"\n]|\\[a-z]|\\[0-9]{3}|\\x[0-9A-Fa-f]{2}|\\[[:punct:]]|\\[ \t]*\n)*\" {
279                           countnewlines();
280                           return dequote(yytext);
281                         }
282 [^\ \t\n\\\"]+          return tokv_barestring;
283 <<EOF>>                 return tokv_eof;
284 \"                      return parseerrprint("misquoted or unterminated string");
285 \\                      return parseerrprint("unexpected backslash");
286 .                       abort(); /* expect lex warning "rule cannot be matched" */
287
288
289 %%
290
291 const char *const builtinservicehelpstrings[]= {
292   "environment",
293   "parameter <parameter>",
294   "version",
295   "toplevel",
296   "override",
297   "shutdown",
298   "reset",
299   "execute",
300   "help",
301    0
302 };
303
304 #include "parser.c"
305