xref: /freebsd/usr.sbin/jail/jailparse.y (revision 086e0149ae56641af245ce472e787c2f67d3aea5)
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 		struct cfjail *j = current_jail;
77 
78 		if (j == NULL) {
79 			if (global_jail == NULL) {
80 				global_jail = add_jail();
81 				global_jail->name = estrdup("*");
82 			}
83 			j = global_jail;
84 		}
85 		TAILQ_INSERT_TAIL(&j->params, $2, tq);
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 		free($2);
145 	}
146 	| error
147 	;
148 
149 /*
150  * A parameter has a fixed name.  A variable definition looks just like a
151  * parameter except that the name is a variable.
152  */
153 name	: STR
154 	{
155 		$$ = emalloc(sizeof(struct cfparam));
156 		$$->name = $1;
157 		TAILQ_INIT(&$$->val);
158 		$$->flags = 0;
159 	}
160 	| VAR
161 	{
162 		$$ = emalloc(sizeof(struct cfparam));
163 		$$->name = $1;
164 		TAILQ_INIT(&$$->val);
165 		$$->flags = PF_VAR;
166 	}
167 	;
168 
169 value	: string
170 	{
171 		$$ = emalloc(sizeof(struct cfstrings));
172 		TAILQ_INIT($$);
173 		TAILQ_INSERT_TAIL($$, $1, tq);
174 	}
175 	| value ',' string
176 	{
177 		$$ = $1;
178 		TAILQ_INSERT_TAIL($$, $3, tq);
179 	}
180 	;
181 
182 /*
183  * Strings may be passed in pieces, because of quoting and/or variable
184  * interpolation.  Reassemble them into a single string.
185  */
186 string	: STR
187 	{
188 		$$ = emalloc(sizeof(struct cfstring));
189 		$$->s = $1;
190 		$$->len = strlen($1);
191 		STAILQ_INIT(&$$->vars);
192 	}
193 	| VAR
194 	{
195 		struct cfvar *v;
196 
197 		$$ = emalloc(sizeof(struct cfstring));
198 		$$->s = estrdup("");
199 		$$->len = 0;
200 		STAILQ_INIT(&$$->vars);
201 		v = emalloc(sizeof(struct cfvar));
202 		v->name = $1;
203 		v->pos = 0;
204 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
205 	}
206 	| string STR1
207 	{
208 		size_t len1;
209 
210 		$$ = $1;
211 		len1 = strlen($2);
212 		$$->s = erealloc($$->s, $$->len + len1 + 1);
213 		strcpy($$->s + $$->len, $2);
214 		free($2);
215 		$$->len += len1;
216 	}
217 	| string VAR1
218 	{
219 		struct cfvar *v;
220 
221 		$$ = $1;
222 		v = emalloc(sizeof(struct cfvar));
223 		v->name = $2;
224 		v->pos = $$->len;
225 		STAILQ_INSERT_TAIL(&$$->vars, v, tq);
226 	}
227 	;
228 
229 %%
230 
231 extern int YYLEX_DECL();
232 
233 extern struct cflex *yyget_extra(void *scanner);
234 extern int yyget_lineno(void *scanner);
235 extern char *yyget_text(void *scanner);
236 
237 static void
238 YYERROR_DECL()
239 {
240 	if (!yyget_text(scanner))
241 		warnx("%s line %d: %s",
242 		    yyget_extra(scanner)->cfname, yyget_lineno(scanner), s);
243 	else if (!yyget_text(scanner)[0])
244 		warnx("%s: unexpected EOF",
245 		    yyget_extra(scanner)->cfname);
246 	else
247 		warnx("%s line %d: %s: %s",
248 		    yyget_extra(scanner)->cfname, yyget_lineno(scanner),
249 		    yyget_text(scanner), s);
250 }
251