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