File: lexer.l

package info (click to toggle)
userv 1.2.0
  • links: PTS
  • area: main
  • in suites: bullseye, buster, sid, stretch
  • size: 700 kB
  • ctags: 1,013
  • sloc: ansic: 4,220; lex: 287; sh: 207; makefile: 206
file content (306 lines) | stat: -rw-r--r-- 13,412 bytes parent folder | download
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
306
/* userv is
 * Copyright 1996-2017 Ian Jackson <ian@davenant.greenend.org.uk>.
 * Copyright 2000      Ben Harris <bjh21@cam.ac.uk>
 * Copyright 2016-2017 Peter Benie <pjb1008@cam.ac.uk>
 *
 * 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"