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