1#include "base.h" 2#include "buffer.h" 3#include "array.h" 4#include "log.h" 5#include "plugin.h" 6 7#include "configfile.h" 8 9#include <string.h> 10#include <stdlib.h> 11 12/** 13 * like all glue code this file contains functions which 14 * are the external interface of lighttpd. The functions 15 * are used by the server itself and the plugins. 16 * 17 * The main-goal is to have a small library in the end 18 * which is linked against both and which will define 19 * the interface itself in the end. 20 * 21 */ 22 23 24/* handle global options */ 25 26/* parse config array */ 27int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) { 28 size_t i; 29 data_unset *du; 30 31 for (i = 0; cv[i].key; i++) { 32 33 if (NULL == (du = array_get_element(ca, cv[i].key))) { 34 /* no found */ 35 36 continue; 37 } 38 39 if ((T_CONFIG_SCOPE_SERVER == cv[i].scope) 40 && (T_CONFIG_SCOPE_SERVER != scope)) { 41 /* server scope options should only be set in server scope, not in conditionals */ 42 log_error_write(srv, __FILE__, __LINE__, "ss", 43 "DEPRECATED: don't set server options in conditionals, variable:", 44 cv[i].key); 45 } 46 47 switch (cv[i].type) { 48 case T_CONFIG_ARRAY: 49 if (du->type == TYPE_ARRAY) { 50 size_t j; 51 data_array *da = (data_array *)du; 52 53 for (j = 0; j < da->value->used; j++) { 54 if (da->value->data[j]->type == TYPE_STRING) { 55 data_string *ds = data_string_init(); 56 57 buffer_copy_buffer(ds->value, ((data_string *)(da->value->data[j]))->value); 58 if (!da->is_index_key) { 59 /* the id's were generated automaticly, as we copy now we might have to renumber them 60 * this is used to prepend server.modules by mod_indexfile as it has to be loaded 61 * before mod_fastcgi and friends */ 62 buffer_copy_buffer(ds->key, ((data_string *)(da->value->data[j]))->key); 63 } 64 65 array_insert_unique(cv[i].destination, (data_unset *)ds); 66 } else { 67 log_error_write(srv, __FILE__, __LINE__, "sssbsd", 68 "the value of an array can only be a string, variable:", 69 cv[i].key, "[", da->value->data[j]->key, "], type:", da->value->data[j]->type); 70 71 return -1; 72 } 73 } 74 } else { 75 log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )"); 76 77 return -1; 78 } 79 break; 80 case T_CONFIG_STRING: 81 if (du->type == TYPE_STRING) { 82 data_string *ds = (data_string *)du; 83 buffer_copy_buffer(cv[i].destination, ds->value); 84 } else { 85 log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\""); 86 87 return -1; 88 } 89 break; 90 case T_CONFIG_SHORT: 91 switch(du->type) { 92 case TYPE_INTEGER: { 93 data_integer *di = (data_integer *)du; 94 95 *((unsigned short *)(cv[i].destination)) = di->value; 96 break; 97 } 98 case TYPE_STRING: { 99 data_string *ds = (data_string *)du; 100 101 /* If the value came from an environment variable, then it is a 102 * data_string, although it may contain a number in ASCII 103 * decimal format. We try to interpret the string as a decimal 104 * short before giving up, in order to support setting numeric 105 * values with environment variables (eg, port number). 106 */ 107 if (ds->value->ptr && *ds->value->ptr) { 108 char *e; 109 long l = strtol(ds->value->ptr, &e, 10); 110 if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) { 111 *((unsigned short *)(cv[i].destination)) = l; 112 break; 113 } 114 } 115 116 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value); 117 118 return -1; 119 } 120 default: 121 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535"); 122 return -1; 123 } 124 break; 125 case T_CONFIG_INT: 126 switch(du->type) { 127 case TYPE_INTEGER: { 128 data_integer *di = (data_integer *)du; 129 130 *((unsigned int *)(cv[i].destination)) = di->value; 131 break; 132 } 133 case TYPE_STRING: { 134 data_string *ds = (data_string *)du; 135 136 if (ds->value->ptr && *ds->value->ptr) { 137 char *e; 138 long l = strtol(ds->value->ptr, &e, 10); 139 if (e != ds->value->ptr && !*e && l >= 0) { 140 *((unsigned int *)(cv[i].destination)) = l; 141 break; 142 } 143 } 144 145 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value); 146 147 return -1; 148 } 149 default: 150 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295"); 151 return -1; 152 } 153 break; 154 case T_CONFIG_BOOLEAN: 155 if (du->type == TYPE_STRING) { 156 data_string *ds = (data_string *)du; 157 158 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) { 159 *((unsigned short *)(cv[i].destination)) = 1; 160 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) { 161 *((unsigned short *)(cv[i].destination)) = 0; 162 } else { 163 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)"); 164 165 return -1; 166 } 167 } else { 168 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\""); 169 170 return -1; 171 } 172 break; 173 case T_CONFIG_LOCAL: 174 case T_CONFIG_UNSET: 175 break; 176 case T_CONFIG_UNSUPPORTED: 177 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination)); 178 179 srv->config_unsupported = 1; 180 181 break; 182 case T_CONFIG_DEPRECATED: 183 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination)); 184 185 srv->config_deprecated = 1; 186 187 break; 188 } 189 } 190 191 return 0; 192} 193 194int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) { 195 size_t i; 196 data_unset *du; 197 198 for (i = 0; cv[i].key; i++) { 199 data_string *touched; 200 201 if (NULL == (du = array_get_element(ca, cv[i].key))) { 202 /* no found */ 203 204 continue; 205 } 206 207 /* touched */ 208 touched = data_string_init(); 209 210 buffer_copy_string_len(touched->value, CONST_STR_LEN("")); 211 buffer_copy_buffer(touched->key, du->key); 212 213 array_insert_unique(srv->config_touched, (data_unset *)touched); 214 } 215 216 return config_insert_values_internal(srv, ca, cv, scope); 217} 218 219static unsigned short sock_addr_get_port(sock_addr *addr) { 220#ifdef HAVE_IPV6 221 return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port); 222#else 223 return ntohs(addr->ipv4.sin_port); 224#endif 225} 226 227static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc); 228 229static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) { 230 buffer *l; 231 server_socket *srv_sock = con->srv_socket; 232 233 /* check parent first */ 234 if (dc->parent && dc->parent->context_ndx) { 235 /** 236 * a nested conditional 237 * 238 * if the parent is not decided yet or false, we can't be true either 239 */ 240 if (con->conf.log_condition_handling) { 241 log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key); 242 } 243 244 switch (config_check_cond_cached(srv, con, dc->parent)) { 245 case COND_RESULT_FALSE: 246 return COND_RESULT_FALSE; 247 case COND_RESULT_UNSET: 248 return COND_RESULT_UNSET; 249 default: 250 break; 251 } 252 } 253 254 if (dc->prev) { 255 /** 256 * a else branch 257 * 258 * we can only be executed, if all of our previous brothers 259 * are false 260 */ 261 if (con->conf.log_condition_handling) { 262 log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key); 263 } 264 265 /* make sure prev is checked first */ 266 config_check_cond_cached(srv, con, dc->prev); 267 268 /* one of prev set me to FALSE */ 269 switch (con->cond_cache[dc->context_ndx].result) { 270 case COND_RESULT_FALSE: 271 return con->cond_cache[dc->context_ndx].result; 272 default: 273 break; 274 } 275 } 276 277 if (!con->conditional_is_valid[dc->comp]) { 278 if (con->conf.log_condition_handling) { 279 log_error_write(srv, __FILE__, __LINE__, "dss", 280 dc->comp, 281 dc->key->ptr, 282 con->conditional_is_valid[dc->comp] ? "yeah" : "nej"); 283 } 284 285 return COND_RESULT_UNSET; 286 } 287 288 /* pass the rules */ 289 290 switch (dc->comp) { 291 case COMP_HTTP_HOST: { 292 char *ck_colon = NULL, *val_colon = NULL; 293 294 if (!buffer_string_is_empty(con->uri.authority)) { 295 296 /* 297 * append server-port to the HTTP_POST if necessary 298 */ 299 300 l = con->uri.authority; 301 302 switch(dc->cond) { 303 case CONFIG_COND_NE: 304 case CONFIG_COND_EQ: 305 ck_colon = strchr(dc->string->ptr, ':'); 306 val_colon = strchr(l->ptr, ':'); 307 308 if (NULL != ck_colon && NULL == val_colon) { 309 /* condition "host:port" but client send "host" */ 310 buffer_copy_buffer(srv->cond_check_buf, l); 311 buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":")); 312 buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr))); 313 l = srv->cond_check_buf; 314 } else if (NULL != val_colon && NULL == ck_colon) { 315 /* condition "host" but client send "host:port" */ 316 buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr); 317 l = srv->cond_check_buf; 318 } 319 break; 320 default: 321 break; 322 } 323#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT 324 } else if (!buffer_string_is_empty(con->tlsext_server_name)) { 325 l = con->tlsext_server_name; 326#endif 327 } else { 328 l = srv->empty_string; 329 } 330 break; 331 } 332 case COMP_HTTP_REMOTE_IP: { 333 char *nm_slash; 334 /* handle remoteip limitations 335 * 336 * "10.0.0.1" is provided for all comparisions 337 * 338 * only for == and != we support 339 * 340 * "10.0.0.1/24" 341 */ 342 343 if ((dc->cond == CONFIG_COND_EQ || 344 dc->cond == CONFIG_COND_NE) && 345 (con->dst_addr.plain.sa_family == AF_INET) && 346 (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) { 347 int nm_bits; 348 long nm; 349 char *err; 350 struct in_addr val_inp; 351 352 if (*(nm_slash+1) == '\0') { 353 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string); 354 355 return COND_RESULT_FALSE; 356 } 357 358 nm_bits = strtol(nm_slash + 1, &err, 10); 359 360 if (*err) { 361 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err); 362 363 return COND_RESULT_FALSE; 364 } 365 366 if (nm_bits > 32 || nm_bits < 0) { 367 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", dc->string, err); 368 369 return COND_RESULT_FALSE; 370 } 371 372 /* take IP convert to the native */ 373 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr); 374#ifdef __WIN32 375 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) { 376 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); 377 378 return COND_RESULT_FALSE; 379 } 380 381#else 382 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) { 383 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); 384 385 return COND_RESULT_FALSE; 386 } 387#endif 388 389 /* build netmask */ 390 nm = nm_bits ? htonl(~((1 << (32 - nm_bits)) - 1)) : 0; 391 392 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) { 393 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; 394 } else { 395 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE; 396 } 397 } else { 398 l = con->dst_addr_buf; 399 } 400 break; 401 } 402 case COMP_HTTP_SCHEME: 403 l = con->uri.scheme; 404 break; 405 406 case COMP_HTTP_URL: 407 l = con->uri.path; 408 break; 409 410 case COMP_HTTP_QUERY_STRING: 411 l = con->uri.query; 412 break; 413 414 case COMP_SERVER_SOCKET: 415 l = srv_sock->srv_token; 416 break; 417 418 case COMP_HTTP_REFERER: { 419 data_string *ds; 420 421 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) { 422 l = ds->value; 423 } else { 424 l = srv->empty_string; 425 } 426 break; 427 } 428 case COMP_HTTP_COOKIE: { 429 data_string *ds; 430 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) { 431 l = ds->value; 432 } else { 433 l = srv->empty_string; 434 } 435 break; 436 } 437 case COMP_HTTP_USER_AGENT: { 438 data_string *ds; 439 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) { 440 l = ds->value; 441 } else { 442 l = srv->empty_string; 443 } 444 break; 445 } 446 case COMP_HTTP_REQUEST_METHOD: { 447 const char *method = get_http_method_name(con->request.http_method); 448 449 /* we only have the request method as const char but we need a buffer for comparing */ 450 451 buffer_copy_string(srv->tmp_buf, method); 452 453 l = srv->tmp_buf; 454 455 break; 456 } 457 case COMP_HTTP_LANGUAGE: { 458 data_string *ds; 459 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) { 460 l = ds->value; 461 } else { 462 l = srv->empty_string; 463 } 464 break; 465 } 466 default: 467 return COND_RESULT_FALSE; 468 } 469 470 if (NULL == l) { 471 if (con->conf.log_condition_handling) { 472 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key, 473 "(", l, ") compare to NULL"); 474 } 475 return COND_RESULT_FALSE; 476 } 477 478 if (con->conf.log_condition_handling) { 479 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key, 480 "(", l, ") compare to ", dc->string); 481 } 482 switch(dc->cond) { 483 case CONFIG_COND_NE: 484 case CONFIG_COND_EQ: 485 if (buffer_is_equal(l, dc->string)) { 486 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; 487 } else { 488 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE; 489 } 490 break; 491#ifdef HAVE_PCRE_H 492 case CONFIG_COND_NOMATCH: 493 case CONFIG_COND_MATCH: { 494 cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; 495 int n; 496 497#ifndef elementsof 498#define elementsof(x) (sizeof(x) / sizeof(x[0])) 499#endif 500 n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0, 501 cache->matches, elementsof(cache->matches)); 502 503 cache->patterncount = n; 504 if (n > 0) { 505 cache->comp_value = l; 506 cache->comp_type = dc->comp; 507 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE; 508 } else { 509 /* cache is already cleared */ 510 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE; 511 } 512 break; 513 } 514#endif 515 default: 516 /* no way */ 517 break; 518 } 519 520 return COND_RESULT_FALSE; 521} 522 523static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) { 524 cond_cache_t *caches = con->cond_cache; 525 526 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) { 527 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) { 528 if (dc->next) { 529 data_config *c; 530 if (con->conf.log_condition_handling) { 531 log_error_write(srv, __FILE__, __LINE__, "s", 532 "setting remains of chaining to false"); 533 } 534 for (c = dc->next; c; c = c->next) { 535 caches[c->context_ndx].result = COND_RESULT_FALSE; 536 } 537 } 538 } 539 caches[dc->context_ndx].comp_type = dc->comp; 540 541 if (con->conf.log_condition_handling) { 542 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx, 543 "(uncached) result:", 544 caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" : 545 (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false")); 546 } 547 } else { 548 if (con->conf.log_condition_handling) { 549 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx, 550 "(cached) result:", 551 caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" : 552 (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false")); 553 } 554 } 555 return caches[dc->context_ndx].result; 556} 557 558/** 559 * reset the config-cache for a named item 560 * 561 * if the item is COND_LAST_ELEMENT we reset all items 562 */ 563void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) { 564 size_t i; 565 566 for (i = 0; i < srv->config_context->used; i++) { 567 if (item == COMP_LAST_ELEMENT || 568 con->cond_cache[i].comp_type == item) { 569 con->cond_cache[i].result = COND_RESULT_UNSET; 570 con->cond_cache[i].patterncount = 0; 571 con->cond_cache[i].comp_value = NULL; 572 } 573 } 574} 575 576/** 577 * reset the config cache to its initial state at connection start 578 */ 579void config_cond_cache_reset(server *srv, connection *con) { 580 size_t i; 581 582 config_cond_cache_reset_all_items(srv, con); 583 584 for (i = 0; i < COMP_LAST_ELEMENT; i++) { 585 con->conditional_is_valid[i] = 0; 586 } 587} 588 589int config_check_cond(server *srv, connection *con, data_config *dc) { 590 if (con->conf.log_condition_handling) { 591 log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ==="); 592 } 593 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE); 594} 595 596int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n) 597{ 598 cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; 599 if (n >= cache->patterncount) { 600 return 0; 601 } 602 603 n <<= 1; /* n *= 2 */ 604 buffer_append_string_len(buf, 605 cache->comp_value->ptr + cache->matches[n], 606 cache->matches[n + 1] - cache->matches[n]); 607 return 1; 608} 609 610