1 %token_prefix TK_ 2 %extra_argument {config_t *ctx} 3 %name configparser 4 5 %include { 6 #include "first.h" 7 #include "configfile.h" 8 #include "buffer.h" 9 #include "array.h" 10 #include "request.h" /* http_request_host_normalize() */ 11 12 #include <assert.h> 13 #include <ctype.h> 14 #include <errno.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 static void configparser_push(config_t *ctx, data_config *dc, int isnew) { 19 if (isnew) { 20 dc->context_ndx = ctx->all_configs->used; 21 force_assert(dc->context_ndx > ctx->current->context_ndx); 22 array_insert_unique(ctx->all_configs, (data_unset *)dc); 23 dc->parent = ctx->current; 24 vector_config_weak_push(&dc->parent->children, dc); 25 } 26 if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) { 27 fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n"); 28 exit(-1); 29 } 30 vector_config_weak_push(&ctx->configs_stack, ctx->current); 31 ctx->current = dc; 32 } 33 34 static data_config *configparser_pop(config_t *ctx) { 35 data_config *old = ctx->current; 36 ctx->current = vector_config_weak_pop(&ctx->configs_stack); 37 return old; 38 } 39 40 /* return a copied variable */ 41 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) { 42 data_unset *du; 43 data_config *dc; 44 45 #if 0 46 fprintf(stderr, "get var %s\n", key->ptr); 47 #endif 48 for (dc = ctx->current; dc; dc = dc->parent) { 49 #if 0 50 fprintf(stderr, "get var on block: %s\n", dc->key->ptr); 51 array_print(dc->value, 0); 52 #endif 53 if (NULL != (du = array_get_element(dc->value, key->ptr))) { 54 return du->copy(du); 55 } 56 } 57 return NULL; 58 } 59 60 /* op1 is to be eat/return by this function if success, op1->key is not cared 61 op2 is left untouch, unreferenced 62 */ 63 data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { 64 /* type mismatch */ 65 if (op1->type != op2->type) { 66 if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) { 67 data_string *ds = (data_string *)op1; 68 buffer_append_int(ds->value, ((data_integer*)op2)->value); 69 return op1; 70 } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) { 71 data_string *ds = data_string_init(); 72 buffer_append_int(ds->value, ((data_integer*)op1)->value); 73 buffer_append_string_buffer(ds->value, ((data_string*)op2)->value); 74 op1->free(op1); 75 return (data_unset *)ds; 76 } else { 77 fprintf(stderr, "data type mismatch, cannot merge\n"); 78 op1->free(op1); 79 return NULL; 80 } 81 } 82 83 switch (op1->type) { 84 case TYPE_STRING: 85 buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value); 86 break; 87 case TYPE_INTEGER: 88 ((data_integer *)op1)->value += ((data_integer *)op2)->value; 89 break; 90 case TYPE_ARRAY: { 91 array *dst = ((data_array *)op1)->value; 92 array *src = ((data_array *)op2)->value; 93 data_unset *du; 94 size_t i; 95 96 for (i = 0; i < src->used; i ++) { 97 du = (data_unset *)src->data[i]; 98 if (du) { 99 if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element(dst, du->key->ptr)) { 100 array_insert_unique(dst, du->copy(du)); 101 } else { 102 fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr); 103 op1->free(op1); 104 return NULL; 105 } 106 } 107 } 108 break; 109 default: 110 force_assert(0); 111 break; 112 } 113 } 114 return op1; 115 } 116 117 } 118 119 %parse_failure { 120 ctx->ok = 0; 121 } 122 123 input ::= metalines. 124 metalines ::= metalines metaline. 125 metalines ::= . 126 metaline ::= varline. 127 metaline ::= global. 128 metaline ::= condlines(A) EOL. { A = NULL; } 129 metaline ::= include. 130 metaline ::= include_shell. 131 metaline ::= EOL. 132 133 %type value {data_unset *} 134 %type expression {data_unset *} 135 %type aelement {data_unset *} 136 %type condline {data_config *} 137 %type condlines {data_config *} 138 %type aelements {array *} 139 %type array {array *} 140 %type key {buffer *} 141 %type stringop {buffer *} 142 143 %type cond {config_cond_t } 144 145 %destructor value { if ($$) $$->free($$); } 146 %destructor expression { if ($$) $$->free($$); } 147 %destructor aelement { if ($$) $$->free($$); } 148 %destructor aelements { array_free($$); } 149 %destructor array { array_free($$); } 150 %destructor key { buffer_free($$); } 151 %destructor stringop { buffer_free($$); } 152 153 %token_type {buffer *} 154 %token_destructor { buffer_free($$); } 155 156 varline ::= key(A) ASSIGN expression(B). { 157 if (ctx->ok) { 158 buffer_copy_buffer(B->key, A); 159 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { 160 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", 161 ctx->current->context_ndx, 162 ctx->current->key->ptr, A->ptr); 163 ctx->ok = 0; 164 } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) { 165 array_insert_unique(ctx->current->value, B); 166 B = NULL; 167 } else { 168 fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", 169 ctx->current->context_ndx, 170 ctx->current->key->ptr, B->key->ptr); 171 ctx->ok = 0; 172 B->free(B); 173 B = NULL; 174 } 175 } 176 buffer_free(A); 177 A = NULL; 178 } 179 180 varline ::= key(A) APPEND expression(B). { 181 if (ctx->ok) { 182 array *vars = ctx->current->value; 183 data_unset *du; 184 185 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { 186 fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n", 187 ctx->current->context_ndx, 188 ctx->current->key->ptr, A->ptr); 189 ctx->ok = 0; 190 } else if (NULL != (du = array_extract_element(vars, A->ptr)) || NULL != (du = configparser_get_variable(ctx, A))) { 191 du = configparser_merge_data(du, B); 192 if (NULL == du) { 193 ctx->ok = 0; 194 } 195 else { 196 buffer_copy_buffer(du->key, A); 197 array_insert_unique(ctx->current->value, du); 198 } 199 B->free(B); 200 } else { 201 buffer_copy_buffer(B->key, A); 202 array_insert_unique(ctx->current->value, B); 203 } 204 buffer_free(A); 205 A = NULL; 206 B = NULL; 207 } 208 } 209 210 key(A) ::= LKEY(B). { 211 if (strchr(B->ptr, '.') == NULL) { 212 A = buffer_init_string("var."); 213 buffer_append_string_buffer(A, B); 214 buffer_free(B); 215 B = NULL; 216 } else { 217 A = B; 218 B = NULL; 219 } 220 } 221 222 expression(A) ::= expression(B) PLUS value(C). { 223 A = NULL; 224 if (ctx->ok) { 225 A = configparser_merge_data(B, C); 226 if (NULL == A) { 227 ctx->ok = 0; 228 } 229 B = NULL; 230 C->free(C); 231 C = NULL; 232 } 233 } 234 235 expression(A) ::= value(B). { 236 A = B; 237 B = NULL; 238 } 239 240 value(A) ::= key(B). { 241 A = NULL; 242 if (ctx->ok) { 243 if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) { 244 char *env; 245 246 if (NULL != (env = getenv(B->ptr + 4))) { 247 data_string *ds; 248 ds = data_string_init(); 249 buffer_append_string(ds->value, env); 250 A = (data_unset *)ds; 251 } 252 else { 253 fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4); 254 ctx->ok = 0; 255 } 256 } else if (NULL == (A = configparser_get_variable(ctx, B))) { 257 fprintf(stderr, "Undefined config variable: %s\n", B->ptr); 258 ctx->ok = 0; 259 } 260 buffer_free(B); 261 B = NULL; 262 } 263 } 264 265 value(A) ::= STRING(B). { 266 A = (data_unset *)data_string_init(); 267 buffer_copy_buffer(((data_string *)(A))->value, B); 268 buffer_free(B); 269 B = NULL; 270 } 271 272 value(A) ::= INTEGER(B). { 273 char *endptr; 274 A = (data_unset *)data_integer_init(); 275 errno = 0; 276 ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10); 277 /* skip trailing whitespace */ 278 if (endptr != B->ptr) while (isspace(*endptr)) endptr++; 279 if (0 != errno || *endptr != '\0') { 280 fprintf(stderr, "error parsing number: '%s'\n", B->ptr); 281 ctx->ok = 0; 282 } 283 buffer_free(B); 284 B = NULL; 285 } 286 value(A) ::= array(B). { 287 A = (data_unset *)data_array_init(); 288 array_free(((data_array *)(A))->value); 289 ((data_array *)(A))->value = B; 290 B = NULL; 291 } 292 array(A) ::= LPARAN RPARAN. { 293 A = array_init(); 294 } 295 array(A) ::= LPARAN aelements(B) RPARAN. { 296 A = B; 297 B = NULL; 298 } 299 300 aelements(A) ::= aelements(C) COMMA aelement(B). { 301 A = NULL; 302 if (ctx->ok) { 303 if (buffer_is_empty(B->key) || 304 NULL == array_get_element(C, B->key->ptr)) { 305 array_insert_unique(C, B); 306 B = NULL; 307 } else { 308 fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n", 309 B->key->ptr); 310 ctx->ok = 0; 311 B->free(B); 312 B = NULL; 313 } 314 315 A = C; 316 C = NULL; 317 } 318 } 319 320 aelements(A) ::= aelements(C) COMMA. { 321 A = C; 322 C = NULL; 323 } 324 325 aelements(A) ::= aelement(B). { 326 A = NULL; 327 if (ctx->ok) { 328 A = array_init(); 329 array_insert_unique(A, B); 330 B = NULL; 331 } 332 } 333 334 aelement(A) ::= expression(B). { 335 A = B; 336 B = NULL; 337 } 338 aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). { 339 A = NULL; 340 if (ctx->ok) { 341 buffer_copy_buffer(C->key, B); 342 buffer_free(B); 343 B = NULL; 344 345 A = C; 346 C = NULL; 347 } 348 } 349 350 eols ::= EOL. 351 eols ::= . 352 353 globalstart ::= GLOBAL. { 354 data_config *dc; 355 dc = (data_config *)array_get_element(ctx->srv->config_context, "global"); 356 force_assert(dc); 357 configparser_push(ctx, dc, 0); 358 } 359 360 global ::= globalstart LCURLY metalines RCURLY. { 361 force_assert(ctx->current); 362 configparser_pop(ctx); 363 force_assert(ctx->current); 364 } 365 366 condlines(A) ::= condlines(B) eols ELSE condline(C). { 367 A = NULL; 368 if (ctx->ok) { 369 if (B->context_ndx >= C->context_ndx) { 370 fprintf(stderr, "unreachable else condition\n"); 371 ctx->ok = 0; 372 } 373 C->prev = B; 374 B->next = C; 375 A = C; 376 B = NULL; 377 C = NULL; 378 } 379 } 380 381 condlines(A) ::= condline(B). { 382 A = B; 383 B = NULL; 384 } 385 386 condline(A) ::= context LCURLY metalines RCURLY. { 387 A = NULL; 388 if (ctx->ok) { 389 data_config *cur; 390 391 cur = ctx->current; 392 configparser_pop(ctx); 393 394 force_assert(cur && ctx->current); 395 396 A = cur; 397 } 398 } 399 400 context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). { 401 data_config *dc; 402 buffer *b, *rvalue, *op; 403 404 if (ctx->ok && D->type != TYPE_STRING) { 405 fprintf(stderr, "rvalue must be string"); 406 ctx->ok = 0; 407 } 408 409 if (ctx->ok) { 410 switch(E) { 411 case CONFIG_COND_NE: 412 op = buffer_init_string("!="); 413 break; 414 case CONFIG_COND_EQ: 415 op = buffer_init_string("=="); 416 break; 417 case CONFIG_COND_NOMATCH: 418 op = buffer_init_string("!~"); 419 break; 420 case CONFIG_COND_MATCH: 421 op = buffer_init_string("=~"); 422 break; 423 default: 424 force_assert(0); 425 return; /* unreachable */ 426 } 427 428 b = buffer_init(); 429 buffer_copy_buffer(b, ctx->current->key); 430 buffer_append_string(b, "/"); 431 buffer_append_string_buffer(b, B); 432 buffer_append_string_buffer(b, C); 433 buffer_append_string_buffer(b, op); 434 rvalue = ((data_string*)D)->value; 435 buffer_append_string_buffer(b, rvalue); 436 437 if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) { 438 configparser_push(ctx, dc, 0); 439 } else { 440 static const struct { 441 comp_key_t comp; 442 char *comp_key; 443 size_t len; 444 } comps[] = { 445 { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) }, 446 { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, 447 { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, 448 { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) }, 449 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, 450 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, 451 { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) }, 452 { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) }, 453 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, 454 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, 455 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, 456 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, 457 { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, 458 { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, 459 { COMP_UNSET, NULL, 0 }, 460 }; 461 size_t i; 462 463 dc = data_config_init(); 464 465 buffer_copy_buffer(dc->key, b); 466 buffer_copy_buffer(dc->op, op); 467 buffer_copy_buffer(dc->comp_key, B); 468 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\"")); 469 buffer_append_string_buffer(dc->comp_key, C); 470 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]")); 471 dc->cond = E; 472 473 for (i = 0; comps[i].comp_key; i ++) { 474 if (buffer_is_equal_string( 475 dc->comp_key, comps[i].comp_key, comps[i].len)) { 476 dc->comp = comps[i].comp; 477 break; 478 } 479 } 480 if (COMP_UNSET == dc->comp) { 481 fprintf(stderr, "error comp_key %s", dc->comp_key->ptr); 482 ctx->ok = 0; 483 } 484 else if (COMP_HTTP_REMOTE_IP == dc->comp 485 && (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) { 486 char * const slash = strchr(rvalue->ptr, '/'); 487 if (NULL != slash && slash != rvalue->ptr){/*(skip AF_UNIX /path/file)*/ 488 char *nptr; 489 const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10); 490 if (*nptr || 0 == nm_bits 491 || nm_bits > (rvalue->ptr[0] == '[' ? 128 : 32)) { 492 /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/ 493 fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr); 494 ctx->ok = 0; 495 } 496 else { 497 int rc; 498 buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/ 499 rc = http_request_host_normalize(rvalue); 500 buffer_append_string_len(rvalue, CONST_STR_LEN("/")); 501 buffer_append_int(rvalue, (int)nm_bits); 502 if (0 != rc) { 503 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 504 ctx->ok = 0; 505 } 506 } 507 } 508 else { 509 if (http_request_host_normalize(rvalue)) { 510 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 511 ctx->ok = 0; 512 } 513 } 514 } 515 else if (COMP_SERVER_SOCKET == dc->comp) { 516 /*(redundant with parsing in network.c; not actually required here)*/ 517 if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/ 518 && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) { 519 if (http_request_host_normalize(rvalue)) { 520 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 521 ctx->ok = 0; 522 } 523 } 524 } 525 else if (COMP_HTTP_HOST == dc->comp) { 526 if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) { 527 if (http_request_host_normalize(rvalue)) { 528 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 529 ctx->ok = 0; 530 } 531 } 532 } 533 534 if (ctx->ok) switch(E) { 535 case CONFIG_COND_NE: 536 case CONFIG_COND_EQ: 537 dc->string = buffer_init_buffer(rvalue); 538 break; 539 case CONFIG_COND_NOMATCH: 540 case CONFIG_COND_MATCH: { 541 #ifdef HAVE_PCRE_H 542 const char *errptr; 543 int erroff, captures; 544 545 if (NULL == (dc->regex = 546 pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) { 547 dc->string = buffer_init_string(errptr); 548 dc->cond = CONFIG_COND_UNSET; 549 550 fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", 551 rvalue->ptr, errptr, erroff); 552 553 ctx->ok = 0; 554 } else if (NULL == (dc->regex_study = 555 pcre_study(dc->regex, 0, &errptr)) && 556 errptr != NULL) { 557 fprintf(stderr, "studying regex failed: %s -> %s\n", 558 rvalue->ptr, errptr); 559 ctx->ok = 0; 560 } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) { 561 fprintf(stderr, "getting capture count for regex failed: %s\n", 562 rvalue->ptr); 563 ctx->ok = 0; 564 } else if (captures > 9) { 565 fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n", 566 rvalue->ptr); 567 ctx->ok = 0; 568 } else { 569 dc->string = buffer_init_buffer(rvalue); 570 } 571 #else 572 fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n" 573 "(perhaps just a missing pcre-devel package ?) \n", 574 B->ptr, C->ptr); 575 ctx->ok = 0; 576 #endif 577 break; 578 } 579 580 default: 581 fprintf(stderr, "unknown condition for $%s[%s]\n", 582 B->ptr, C->ptr); 583 ctx->ok = 0; 584 break; 585 } 586 587 if (ctx->ok) { 588 configparser_push(ctx, dc, 1); 589 } else { 590 dc->free((data_unset*) dc); 591 } 592 } 593 594 buffer_free(b); 595 buffer_free(op); 596 buffer_free(B); 597 B = NULL; 598 buffer_free(C); 599 C = NULL; 600 D->free(D); 601 D = NULL; 602 } 603 } 604 cond(A) ::= EQ. { 605 A = CONFIG_COND_EQ; 606 } 607 cond(A) ::= MATCH. { 608 A = CONFIG_COND_MATCH; 609 } 610 cond(A) ::= NE. { 611 A = CONFIG_COND_NE; 612 } 613 cond(A) ::= NOMATCH. { 614 A = CONFIG_COND_NOMATCH; 615 } 616 617 stringop(A) ::= expression(B). { 618 A = NULL; 619 if (ctx->ok) { 620 if (B->type == TYPE_STRING) { 621 A = buffer_init_buffer(((data_string*)B)->value); 622 } else if (B->type == TYPE_INTEGER) { 623 A = buffer_init(); 624 buffer_copy_int(A, ((data_integer *)B)->value); 625 } else { 626 fprintf(stderr, "operand must be string"); 627 ctx->ok = 0; 628 } 629 } 630 B->free(B); 631 B = NULL; 632 } 633 634 include ::= INCLUDE stringop(A). { 635 if (ctx->ok) { 636 if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) { 637 ctx->ok = 0; 638 } 639 buffer_free(A); 640 A = NULL; 641 } 642 } 643 644 include_shell ::= INCLUDE_SHELL stringop(A). { 645 if (ctx->ok) { 646 if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) { 647 ctx->ok = 0; 648 } 649 buffer_free(A); 650 A = NULL; 651 } 652 } 653