xref: /freebsd/usr.sbin/jail/jailparse.y (revision 19fae0f66023a97a9b464b3beeeabb2081f575b3)
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 __FBSDID("$FreeBSD$");
32 
33 #include <err.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "jailp.h"
38 
39 #ifdef DEBUG
40 #define YYDEBUG 1
41 #endif
42 
43 static struct cfjail *current_jail;
44 static struct cfjail *global_jail;
45 %}
46 
47 %union {
48 	struct cfparam		*p;
49 	struct cfstrings	*ss;
50 	struct cfstring		*s;
51 	char			*cs;
52 }
53 
54 %token      PLEQ
55 %token <cs> STR STR1 VAR VAR1
56 
57 %type <p>  param name
58 %type <ss> value
59 %type <s>  string
60 
61 %pure-parser
62 
63 %lex-param { void *scanner }
64 %parse-param { void *scanner }
65 
66 %%
67 
68 /*
69  * A config file is a list of jails and parameters.  Parameters are
70  * added to the current jail, otherwise to a global pesudo-jail.
71  */
72 conf	:
73 	| conf jail
74 	| conf param ';'
75 	{
76 		if (!special_param($2, scanner)) {
77 			struct cfjail *j = current_jail;
78 
79 			if (j == NULL) {
80 				if (global_jail == NULL) {
81 					global_jail = add_jail();
82 					global_jail->name = estrdup("*");
83 				}
84 				j = global_jail;
85 			}
86 			TAILQ_INSERT_TAIL(&j->params, $2, tq);
87 		}
88 	}
89 	| conf ';'
90 	;
91 
92 jail	: jail_name '{' conf '}'
93 	{
94 		current_jail = current_jail->cfparent;
95 	}
96 	;
97 
98 jail_name : STR
99 	{
100 		struct cfjail *j = add_jail();
101 
102 		if (current_jail == NULL)
103 			j->name = $1;
104 		else {
105 			/*
106 			 * A nested jail definition becomes
107 			 * a hierarchically-named sub-jail.
108 			 */
109 			size_t parentlen = strlen(current_jail->name);
110 			j->name = emalloc(parentlen + strlen($1) + 2);
111 			strcpy(j->name, current_jail->name);
112 			j->name[parentlen++] = '.';
113 			strcpy(j->name + parentlen, $1);
114 			free($1);
115 		}
116 		j->cfparent = current_jail;
117 		current_jail = j;
118 	}
119 	;
120 
121 /*
122  * Parameters have a name and an optional list of value strings,
123  * which may have "+=" or "=" preceding them.
124  */
125 param	: name
126 	{
127 		$$ = $1;
128 	}
129 	| name '=' value
130 	{
131 		$$ = $1;
132 		TAILQ_CONCAT(&$$->val, $3, tq);
133 		free($3);
134 	}
135 	| name PLEQ value
136 	{
137 		$$ = $1;
138 		TAILQ_CONCAT(&$$->val, $3, tq);
139 		$$->flags |= PF_APPEND;
140 		free($3);
141 	}
142 	| name value
143 	{
144 		$$ = $1;
145 		TAILQ_CONCAT(&$$->val, $2, tq);
146 		$$->flags |= PF_NAMEVAL;
147 		free($2);
148 	}
149 	| error
150 	;
151 
152 /*
153  * A parameter has a fixed name.  A variable definition looks just like a
154  * parameter except that the name is a variable.
155  */
156 name	: STR
157 	{
158 		$$ = emalloc(sizeof(struct cfparam));
159 		$$->name = $1;
160 		TAILQ_INIT(&$$->val);
161 		$$->flags = 0;
162 	}
163 	| VAR
164 	{
165 		$$ = emalloc(sizeof(struct cfparam));
166 		$$->name = $1;
167 		TAILQ_INIT(&$$->val);
168 		$$->flags = PF_VAR;
169 	}
170 	;
171 
172 value	: string
173 	{
174 		$$ = emalloc(sizeof(struct cfstrings));
175 		TAILQ_INIT($$);
176 		TAILQ_INSERT_TAIL($$, $1, tq);
177 	}
178 	| value ',' string
179 	{
180 		$$ = $1;
181 		TAILQ_INSERT_TAIL($$, $3, tq);
182 	}
183 	;
184 
185 /*
186  * Strings may be passed in pieces, because of quoting and/or variable
187  * interpolation.  Reassemble them into a single string.
188  */
189 string	: STR
190 	{
191 		$$ = emalloc(sizeof(struct cfstring));
192 		$$->s = $1;
193 		$$->len = strlen($1);
194 		STAILQ_INIT(&$$->vars);
195 	}
196 	| VAR
197 	{
198 		struct cfvar *v;
199 
200 		$$ = emalloc(sizeof(struct cfstring));
201 		$$->s = estrdup("");
202 		$$->len = 0;
203 		STAILQ_INIT(&$$->vars);
204 		v = emalloc(sizeof(struct cfvar));
205 		v->name = $1;
206 		v->pos = 0;
207 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
208 	}
209 	| string STR1
210 	{
211 		size_t len1;
212 
213 		$$ = $1;
214 		len1 = strlen($2);
215 		$$->s = erealloc($$->s, $$->len + len1 + 1);
216 		strcpy($$->s + $$->len, $2);
217 		free($2);
218 		$$->len += len1;
219 	}
220 	| string VAR1
221 	{
222 		struct cfvar *v;
223 
224 		$$ = $1;
225 		v = emalloc(sizeof(struct cfvar));
226 		v->name = $2;
227 		v->pos = $$->len;
228 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
229 	}
230 	;
231 
232 %%
233 
234 extern int YYLEX_DECL();
235 
236 static void
237 YYERROR_DECL()
238 {
239 	if (!yyget_text(scanner))
240 		warnx("%s line %d: %s",
241 		    yyget_extra(scanner)->cfname, yyget_lineno(scanner), s);
242 	else if (!yyget_text(scanner)[0])
243 		warnx("%s: unexpected EOF",
244 		    yyget_extra(scanner)->cfname);
245 	else
246 		warnx("%s line %d: %s: %s",
247 		    yyget_extra(scanner)->cfname, yyget_lineno(scanner),
248 		    yyget_text(scanner), s);
249 }
250 
251 /* Handle special parameters (i.e. the include directive).
252  * Return true if the parameter was specially handled.
253  */
254 static int
255 special_param(struct cfparam *p, void *scanner)
256 {
257 	if ((p->flags & (PF_VAR | PF_APPEND | PF_NAMEVAL)) != PF_NAMEVAL
258 	    || strcmp(p->name, ".include"))
259 		return 0;
260 	struct cfstring *s;
261 	TAILQ_FOREACH(s, &p->val, tq) {
262 		if (STAILQ_EMPTY(&s->vars))
263 			include_config(scanner, s->s);
264 		else {
265 			warnx("%s line %d: "
266 			    "variables not permitted in '.include' filename",
267 			    yyget_extra(scanner)->cfname,
268 			    yyget_lineno(scanner));
269 			yyget_extra(scanner)->error = 1;
270 		}
271 	}
272 	free_param_strings(p);
273 	free(p);
274 	return 1;
275 }
276