xref: /freebsd/usr.sbin/jail/jailparse.y (revision f5463265955b829775bbb32e1fd0bc11dafc36ce)
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause
4  *
5  * Copyright (c) 2011 James Gritton
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 #include <err.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "jailp.h"
36 
37 #ifdef DEBUG
38 #define YYDEBUG 1
39 #endif
40 
41 static struct cfjail *current_jail;
42 static struct cfjail *global_jail;
43 %}
44 
45 %union {
46 	struct cfparam		*p;
47 	struct cfstrings	*ss;
48 	struct cfstring		*s;
49 	char			*cs;
50 }
51 
52 %token      PLEQ
53 %token <cs> STR STR1 VAR VAR1
54 
55 %type <p>  param name
56 %type <ss> value
57 %type <s>  string
58 
59 %pure-parser
60 
61 %lex-param { void *scanner }
62 %parse-param { void *scanner }
63 
64 %%
65 
66 /*
67  * A config file is a list of jails and parameters.  Parameters are
68  * added to the current jail, otherwise to a global pesudo-jail.
69  */
70 conf	:
71 	| conf jail
72 	| conf param ';'
73 	{
74 		if (!special_param($2, scanner)) {
75 			struct cfjail *j = current_jail;
76 
77 			if (j == NULL) {
78 				if (global_jail == NULL) {
79 					global_jail = add_jail();
80 					global_jail->name = estrdup("*");
81 				}
82 				j = global_jail;
83 			}
84 			TAILQ_INSERT_TAIL(&j->params, $2, tq);
85 		}
86 	}
87 	| conf ';'
88 	;
89 
90 jail	: jail_name '{' conf '}'
91 	{
92 		current_jail = current_jail->cfparent;
93 	}
94 	;
95 
96 jail_name : STR
97 	{
98 		struct cfjail *j = add_jail();
99 
100 		if (current_jail == NULL)
101 			j->name = $1;
102 		else {
103 			/*
104 			 * A nested jail definition becomes
105 			 * a hierarchically-named sub-jail.
106 			 */
107 			size_t parentlen = strlen(current_jail->name);
108 			j->name = emalloc(parentlen + strlen($1) + 2);
109 			strcpy(j->name, current_jail->name);
110 			j->name[parentlen++] = '.';
111 			strcpy(j->name + parentlen, $1);
112 			free($1);
113 		}
114 		j->cfparent = current_jail;
115 		current_jail = j;
116 	}
117 	;
118 
119 /*
120  * Parameters have a name and an optional list of value strings,
121  * which may have "+=" or "=" preceding them.
122  */
123 param	: name
124 	{
125 		$$ = $1;
126 	}
127 	| name '=' value
128 	{
129 		$$ = $1;
130 		TAILQ_CONCAT(&$$->val, $3, tq);
131 		free($3);
132 	}
133 	| name PLEQ value
134 	{
135 		$$ = $1;
136 		TAILQ_CONCAT(&$$->val, $3, tq);
137 		$$->flags |= PF_APPEND;
138 		free($3);
139 	}
140 	| name value
141 	{
142 		$$ = $1;
143 		TAILQ_CONCAT(&$$->val, $2, tq);
144 		$$->flags |= PF_NAMEVAL;
145 		free($2);
146 	}
147 	| error
148 	;
149 
150 /*
151  * A parameter has a fixed name.  A variable definition looks just like a
152  * parameter except that the name is a variable.
153  */
154 name	: STR
155 	{
156 		$$ = emalloc(sizeof(struct cfparam));
157 		$$->name = $1;
158 		TAILQ_INIT(&$$->val);
159 		$$->flags = 0;
160 	}
161 	| VAR
162 	{
163 		$$ = emalloc(sizeof(struct cfparam));
164 		$$->name = $1;
165 		TAILQ_INIT(&$$->val);
166 		$$->flags = PF_VAR;
167 	}
168 	;
169 
170 value	: string
171 	{
172 		$$ = emalloc(sizeof(struct cfstrings));
173 		TAILQ_INIT($$);
174 		TAILQ_INSERT_TAIL($$, $1, tq);
175 	}
176 	| value ',' string
177 	{
178 		$$ = $1;
179 		TAILQ_INSERT_TAIL($$, $3, tq);
180 	}
181 	;
182 
183 /*
184  * Strings may be passed in pieces, because of quoting and/or variable
185  * interpolation.  Reassemble them into a single string.
186  */
187 string	: STR
188 	{
189 		$$ = emalloc(sizeof(struct cfstring));
190 		$$->s = $1;
191 		$$->len = strlen($1);
192 		STAILQ_INIT(&$$->vars);
193 	}
194 	| VAR
195 	{
196 		struct cfvar *v;
197 
198 		$$ = emalloc(sizeof(struct cfstring));
199 		$$->s = estrdup("");
200 		$$->len = 0;
201 		STAILQ_INIT(&$$->vars);
202 		v = emalloc(sizeof(struct cfvar));
203 		v->name = $1;
204 		v->pos = 0;
205 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
206 	}
207 	| string STR1
208 	{
209 		size_t len1;
210 
211 		$$ = $1;
212 		len1 = strlen($2);
213 		$$->s = erealloc($$->s, $$->len + len1 + 1);
214 		strcpy($$->s + $$->len, $2);
215 		free($2);
216 		$$->len += len1;
217 	}
218 	| string VAR1
219 	{
220 		struct cfvar *v;
221 
222 		$$ = $1;
223 		v = emalloc(sizeof(struct cfvar));
224 		v->name = $2;
225 		v->pos = $$->len;
226 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
227 	}
228 	;
229 
230 %%
231 
232 extern int YYLEX_DECL();
233 
234 static void
235 YYERROR_DECL()
236 {
237 	struct cflex *cflex = yyget_extra(scanner);
238 
239 	if (!yyget_text(scanner))
240 		warnx("%s line %d: %s",
241 		    cflex->cfname, yyget_lineno(scanner), s);
242 	else if (!yyget_text(scanner)[0])
243 		warnx("%s: unexpected EOF",
244 		    cflex->cfname);
245 	else
246 		warnx("%s line %d: %s: %s",
247 		    cflex->cfname, yyget_lineno(scanner),
248 		    yyget_text(scanner), s);
249 	cflex->error = 1;
250 }
251 
252 /* Handle special parameters (i.e. the include directive).
253  * Return true if the parameter was specially handled.
254  */
255 static int
256 special_param(struct cfparam *p, void *scanner)
257 {
258 	if ((p->flags & (PF_VAR | PF_APPEND | PF_NAMEVAL)) != PF_NAMEVAL
259 	    || strcmp(p->name, ".include"))
260 		return 0;
261 	struct cfstring *s;
262 	TAILQ_FOREACH(s, &p->val, tq) {
263 		if (STAILQ_EMPTY(&s->vars))
264 			include_config(scanner, s->s);
265 		else {
266 			warnx("%s line %d: "
267 			    "variables not permitted in '.include' filename",
268 			    yyget_extra(scanner)->cfname,
269 			    yyget_lineno(scanner));
270 			yyget_extra(scanner)->error = 1;
271 		}
272 	}
273 	free_param_strings(p);
274 	free(p);
275 	return 1;
276 }
277