1 #include "first.h" 2 3 #include "base.h" 4 #include "burl.h" 5 #include "chunk.h" 6 #include "ck.h" 7 #include "fdevent.h" 8 #include "fdlog.h" 9 #include "http_etag.h" 10 #include "keyvalue.h" 11 #include "log.h" 12 13 #include "configparser.h" 14 #include "configfile.h" 15 #include "plugin.h" 16 #include "reqpool.h" 17 #include "sock_addr.h" 18 #include "stat_cache.h" 19 #include "sys-crypto.h" 20 21 #include <sys/stat.h> 22 #ifdef HAVE_SYS_WAIT_H 23 #include <sys/wait.h> 24 #endif 25 26 #include <stdlib.h> 27 #include <fcntl.h> 28 #include <unistd.h> 29 #include <errno.h> 30 #include <string.h> 31 #include <limits.h> 32 #include <glob.h> 33 34 #ifdef HAVE_SYSLOG_H 35 # include <syslog.h> 36 #endif 37 38 #ifdef HAVE_PCRE2_H 39 #define PCRE2_CODE_UNIT_WIDTH 8 40 #include <pcre2.h> 41 #endif 42 43 #ifndef PATH_MAX 44 #define PATH_MAX 4096 45 #endif 46 47 typedef struct { 48 PLUGIN_DATA; 49 request_config defaults; 50 } config_data_base; 51 52 static void config_free_config(void * const p_d) { 53 plugin_data_base * const p = p_d; 54 if (NULL == p) return; 55 if (NULL == p->cvlist) { free(p); return; } 56 /* (init i to 0 if global context; to 1 to skip empty global context) */ 57 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 58 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 59 for (; -1 != cpv->k_id; ++cpv) { 60 switch (cpv->k_id) { 61 case 18:/* server.kbytes-per-second */ 62 if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v); 63 break; 64 default: 65 break; 66 } 67 } 68 } 69 free(p->cvlist); 70 free(p); 71 } 72 73 void config_reset_config_bytes_sec(void * const p_d) { 74 plugin_data_base * const p = p_d; 75 if (NULL == p->cvlist) return; 76 /* (init i to 0 if global context; to 1 to skip empty global context) */ 77 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 78 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 79 for (; -1 != cpv->k_id; ++cpv) { 80 switch (cpv->k_id) { 81 case 18:/* server.kbytes-per-second */ 82 if (cpv->vtype == T_CONFIG_LOCAL) ((off_t *)cpv->v.v)[0] = 0; 83 break; 84 default: 85 break; 86 } 87 } 88 } 89 } 90 91 static void config_merge_config_cpv(request_config * const pconf, const config_plugin_value_t * const cpv) { 92 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 93 case 0: /* server.document-root */ 94 pconf->document_root = cpv->v.b; 95 break; 96 case 1: /* server.name */ 97 pconf->server_name = cpv->v.b; 98 break; 99 case 2: /* server.tag */ 100 pconf->server_tag = cpv->v.b; 101 break; 102 case 3: /* server.max-request-size */ 103 pconf->max_request_size = cpv->v.u; 104 break; 105 case 4: /* server.max-keep-alive-requests */ 106 pconf->max_keep_alive_requests = cpv->v.shrt; 107 break; 108 case 5: /* server.max-keep-alive-idle */ 109 pconf->max_keep_alive_idle = cpv->v.shrt; 110 break; 111 case 6: /* server.max-read-idle */ 112 pconf->max_read_idle = cpv->v.shrt; 113 break; 114 case 7: /* server.max-write-idle */ 115 pconf->max_write_idle = cpv->v.shrt; 116 break; 117 case 8: /* server.errorfile-prefix */ 118 pconf->errorfile_prefix = cpv->v.b; 119 break; 120 case 9: /* server.error-handler */ 121 pconf->error_handler = cpv->v.b; 122 break; 123 case 10:/* server.error-handler-404 */ 124 pconf->error_handler_404 = cpv->v.b; 125 break; 126 case 11:/* server.error-intercept */ 127 pconf->error_intercept = (0 != cpv->v.u); 128 break; 129 case 12:/* server.force-lowercase-filenames */ 130 pconf->force_lowercase_filenames = (0 != cpv->v.u); 131 break; 132 case 13:/* server.follow-symlink */ 133 pconf->follow_symlink = (0 != cpv->v.u); 134 break; 135 case 14:/* server.protocol-http11 */ 136 pconf->allow_http11 = (0 != cpv->v.u); 137 break; 138 case 15:/* server.range-requests */ 139 pconf->range_requests = (0 != cpv->v.u); 140 break; 141 case 16:/* server.stream-request-body */ 142 pconf->stream_request_body = cpv->v.shrt; 143 break; 144 case 17:/* server.stream-response-body */ 145 pconf->stream_response_body = cpv->v.shrt; 146 break; 147 case 18:/* server.kbytes-per-second */ 148 pconf->global_bytes_per_second = (unsigned int)((off_t *)cpv->v.v)[1]; 149 pconf->global_bytes_per_second_cnt_ptr = cpv->v.v; 150 break; 151 case 19:/* connection.kbytes-per-second */ 152 pconf->bytes_per_second = (unsigned int)cpv->v.shrt << 10;/* (*=1024) */ 153 break; 154 case 20:/* mimetype.assign */ 155 pconf->mimetypes = cpv->v.a; 156 break; 157 case 21:/* mimetype.use-xattr */ 158 pconf->use_xattr = (0 != cpv->v.u); 159 break; 160 case 22:/* etag.use-inode */ 161 cpv->v.u 162 ? (pconf->etag_flags |= ETAG_USE_INODE) 163 : (pconf->etag_flags &= ~ETAG_USE_INODE); 164 break; 165 case 23:/* etag.use-mtime */ 166 cpv->v.u 167 ? (pconf->etag_flags |= ETAG_USE_MTIME) 168 : (pconf->etag_flags &= ~ETAG_USE_MTIME); 169 break; 170 case 24:/* etag.use-size */ 171 cpv->v.u 172 ? (pconf->etag_flags |= ETAG_USE_SIZE) 173 : (pconf->etag_flags &= ~ETAG_USE_SIZE); 174 break; 175 case 25:/* debug.log-condition-handling */ 176 pconf->log_condition_handling = (0 != cpv->v.u); 177 break; 178 case 26:/* debug.log-file-not-found */ 179 pconf->log_file_not_found = (0 != cpv->v.u); 180 break; 181 case 27:/* debug.log-request-handling */ 182 pconf->log_request_handling = (0 != cpv->v.u); 183 break; 184 case 28:/* debug.log-request-header */ 185 pconf->log_request_header = (0 != cpv->v.u); 186 break; 187 case 29:/* debug.log-response-header */ 188 pconf->log_response_header = (0 != cpv->v.u); 189 break; 190 case 30:/* debug.log-timeouts */ 191 pconf->log_timeouts = (0 != cpv->v.u); 192 break; 193 case 31:/* debug.log-state-handling */ 194 pconf->log_state_handling = (0 != cpv->v.u); 195 break; 196 case 32:/* server.errorlog */ 197 if (cpv->vtype == T_CONFIG_LOCAL) pconf->errh = cpv->v.v; 198 break; 199 case 33:/* server.breakagelog */ 200 if (cpv->vtype == T_CONFIG_LOCAL) pconf->serrh = cpv->v.v; 201 break; 202 default:/* should not happen */ 203 return; 204 } 205 } 206 207 static void config_merge_config(request_config * const pconf, const config_plugin_value_t *cpv) { 208 do { 209 config_merge_config_cpv(pconf, cpv); 210 } while ((++cpv)->k_id != -1); 211 } 212 213 void config_patch_config(request_st * const r) { 214 config_data_base * const p = r->con->config_data_base; 215 216 /* performed by request_config_reset() */ 217 /*memcpy(&r->conf, &p->defaults, sizeof(request_config));*/ 218 219 for (int i = 1, used = p->nconfig; i < used; ++i) { 220 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 221 config_merge_config(&r->conf, p->cvlist + p->cvlist[i].v.u2[0]); 222 } 223 } 224 225 #if 0 /*(moved to reqpool.c:request_config_reset())*/ 226 void config_reset_config(request_st * const r) { 227 /* initialize request_config (r->conf) from top-level request_config */ 228 config_data_base * const p = r->con->config_data_base; 229 memcpy(&r->conf, &p->defaults, sizeof(request_config)); 230 } 231 #endif 232 233 static void config_burl_normalize_cond (server * const srv) { 234 buffer * const tb = srv->tmp_buf; 235 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 236 data_config * const config =(data_config *)srv->config_context->data[i]; 237 if (COMP_HTTP_QUERY_STRING != config->comp) continue; 238 switch(config->cond) { 239 case CONFIG_COND_NE: 240 case CONFIG_COND_EQ: 241 case CONFIG_COND_PREFIX: 242 case CONFIG_COND_SUFFIX: 243 /* (can use this routine as long as it does not perform 244 * any regex-specific normalization of first arg) */ 245 pcre_keyvalue_burl_normalize_key(&config->string, tb); 246 break; 247 case CONFIG_COND_NOMATCH: 248 case CONFIG_COND_MATCH: 249 pcre_keyvalue_burl_normalize_key(&config->string, tb); 250 break; 251 default: 252 break; 253 } 254 } 255 } 256 257 static int config_pcre_keyvalue (server * const srv) { 258 const int pcre_jit = config_feature_bool(srv, "server.pcre_jit", 1); 259 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 260 data_config * const dc = (data_config *)srv->config_context->data[i]; 261 if (dc->cond != CONFIG_COND_NOMATCH && dc->cond != CONFIG_COND_MATCH) 262 continue; 263 if (!data_config_pcre_compile(dc, pcre_jit, srv->errh)) 264 return 0; 265 } 266 267 return 1; 268 } 269 270 #ifdef USE_OPENSSL_CRYPTO 271 static void config_warn_openssl_module (server *srv) { 272 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 273 const data_config *config = (data_config const*)srv->config_context->data[i]; 274 for (uint32_t j = 0; j < config->value->used; ++j) { 275 data_unset *du = config->value->data[j]; 276 if (0 == strncmp(du->key.ptr, "ssl.", sizeof("ssl.")-1)) { 277 /* mod_openssl should be loaded after mod_extforward */ 278 array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_openssl")); 279 log_error(srv->errh, __FILE__, __LINE__, 280 "Warning: please add \"mod_openssl\" to server.modules list " 281 "in lighttpd.conf. A future release of lighttpd 1.4.x " 282 "*will not* automatically load mod_openssl and lighttpd " 283 "*will not* use SSL/TLS where your lighttpd.conf contains " 284 "ssl.* directives"); 285 return; 286 } 287 } 288 } 289 } 290 #endif 291 292 static void config_check_module_duplicates (server *srv) { 293 int dups = 0; 294 data_string ** const data = (data_string **)srv->srvconf.modules->data; 295 const uint32_t used = srv->srvconf.modules->used; 296 for (uint32_t i = 0; i < used; ++i) { 297 const buffer * const m = &data[i]->value; 298 for (uint32_t j = i+1; j < used; ++j) { 299 if (buffer_is_equal(m, &data[j]->value)) { 300 ++dups; 301 break; 302 } 303 } 304 } 305 if (!dups) return; 306 307 array * const modules = array_init(used - dups); 308 for (uint32_t i = 0; i < used; ++i) { 309 const buffer * const m = &data[i]->value; 310 uint32_t j; 311 for (j = 0; j < modules->used; ++j) { 312 buffer *n = &((data_string *)modules->data[j])->value; 313 if (buffer_is_equal(m, n)) break; /* duplicate */ 314 } 315 if (j == modules->used) 316 array_insert_value(modules, BUF_PTR_LEN(m)); 317 } 318 array_free(srv->srvconf.modules); 319 srv->srvconf.modules = modules; 320 } 321 322 __attribute_pure__ 323 static const char * config_has_opt_and_value (const server * const srv, const char * const opt, const uint32_t olen, const char * const v, const uint32_t vlen) { 324 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 325 const data_config * const config = 326 (data_config const *)srv->config_context->data[i]; 327 const data_string * const ds = 328 (data_string *)array_get_element_klen(config->value, opt, olen); 329 if (NULL != ds && ds->type == TYPE_STRING 330 && buffer_eq_slen(&ds->value, v, vlen)) 331 return v; 332 } 333 return NULL; 334 } 335 336 static void config_compat_module_prepend (server *srv, const char *module, uint32_t len) { 337 array *modules = array_init(srv->srvconf.modules->used+4); 338 array_insert_value(modules, module, len); 339 340 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 341 data_string *ds = (data_string *)srv->srvconf.modules->data[i]; 342 array_insert_value(modules, BUF_PTR_LEN(&ds->value)); 343 } 344 345 array_free(srv->srvconf.modules); 346 srv->srvconf.modules = modules; 347 } 348 349 static void config_warn_authn_module (server *srv, const char *module, uint32_t len, const char *v) { 350 buffer * const tb = srv->tmp_buf; 351 buffer_copy_string_len(tb, CONST_STR_LEN("mod_authn_")); 352 buffer_append_string_len(tb, module, len); 353 array_insert_value(srv->srvconf.modules, BUF_PTR_LEN(tb)); 354 log_error(srv->errh, __FILE__, __LINE__, 355 "Warning: please add \"mod_authn_%s\" to server.modules list " 356 "in lighttpd.conf. A future release of lighttpd 1.4.x will " 357 "not automatically load mod_authn_%s and lighttpd will fail " 358 "to start up since your lighttpd.conf uses auth.backend = \"%s\".", 359 module, module, v); 360 } 361 362 static void config_compat_module_load (server *srv) { 363 int prepend_mod_indexfile = 1; 364 int append_mod_dirlisting = 1; 365 int append_mod_staticfile = 1; 366 int append_mod_authn_file = 1; 367 int append_mod_authn_ldap = 1; 368 int append_mod_openssl = 1; 369 int contains_mod_auth = 0; 370 int prepend_mod_auth = 0; 371 int prepend_mod_vhostdb = 0; 372 const char *dyn_name = NULL; 373 374 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 375 buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value; 376 377 if (buffer_eq_slen(m, CONST_STR_LEN("mod_indexfile"))) 378 prepend_mod_indexfile = 0; 379 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_staticfile"))) 380 append_mod_staticfile = 0; 381 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_dirlisting"))) 382 append_mod_dirlisting = 0; 383 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_gnutls"))) 384 append_mod_openssl = 0; 385 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_mbedtls"))) 386 append_mod_openssl = 0; 387 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_nss"))) 388 append_mod_openssl = 0; 389 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_openssl"))) 390 append_mod_openssl = 0; 391 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_wolfssl"))) 392 append_mod_openssl = 0; 393 else if (0 == strncmp(m->ptr, "mod_auth", sizeof("mod_auth")-1)) { 394 if (buffer_eq_slen(m, CONST_STR_LEN("mod_auth"))) { 395 if (!contains_mod_auth) { 396 contains_mod_auth = 1; 397 if (dyn_name) 398 log_error(srv->errh, __FILE__, __LINE__, 399 "Warning: mod_auth should be listed in server.modules" 400 " before dynamic backends such as %s", dyn_name); 401 } 402 } 403 else if (!contains_mod_auth) 404 prepend_mod_auth = 1; 405 406 if (buffer_eq_slen(m, CONST_STR_LEN("mod_authn_file"))) 407 append_mod_authn_file = 0; 408 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_authn_ldap"))) 409 append_mod_authn_ldap = 0; 410 } 411 else if (0 == strncmp(m->ptr, "mod_vhostdb", sizeof("mod_vhostdb")-1)) { 412 if (buffer_eq_slen(m, CONST_STR_LEN("mod_vhostdb"))) 413 prepend_mod_vhostdb |= 2; 414 else if (!(prepend_mod_vhostdb & 2)) 415 prepend_mod_vhostdb |= 1; 416 } 417 else if ( 0 == strncmp(m->ptr, "mod_ajp13", 418 sizeof("mod_ajp13")-1) 419 || 0 == strncmp(m->ptr, "mod_cgi", 420 sizeof("mod_cgi")-1) 421 || 0 == strncmp(m->ptr, "mod_fastcgi", 422 sizeof("mod_fastcgi")-1) 423 || 0 == strncmp(m->ptr, "mod_proxy", 424 sizeof("mod_proxy")-1) 425 || 0 == strncmp(m->ptr, "mod_scgi", 426 sizeof("mod_scgi")-1) 427 || 0 == strncmp(m->ptr, "mod_sockproxy", 428 sizeof("mod_sockproxy")-1) 429 || 0 == strncmp(m->ptr, "mod_wstunnel", 430 sizeof("mod_wstunnel")-1)) { 431 if (NULL == dyn_name) 432 dyn_name = m->ptr; 433 } 434 } 435 436 /* prepend default modules */ 437 438 if (prepend_mod_indexfile) { 439 /* mod_indexfile has to be loaded before mod_fastcgi and friends */ 440 config_compat_module_prepend(srv, CONST_STR_LEN("mod_indexfile")); 441 } 442 443 /* append default modules */ 444 445 if (append_mod_dirlisting) { 446 array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_dirlisting")); 447 } 448 449 if (append_mod_staticfile) { 450 array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_staticfile")); 451 } 452 453 if (append_mod_openssl) { 454 #ifdef USE_OPENSSL_CRYPTO 455 config_warn_openssl_module(srv); 456 #endif 457 } 458 459 /* mod_auth.c,mod_auth_api.c auth backends were split into separate modules 460 * Automatically load auth backend modules for compatibility with 461 * existing lighttpd 1.4.x configs */ 462 if (contains_mod_auth) { 463 if (append_mod_authn_file) { 464 const char *v; 465 if ( (v=config_has_opt_and_value(srv,CONST_STR_LEN("auth.backend"), 466 CONST_STR_LEN("htdigest"))) 467 ||(v=config_has_opt_and_value(srv,CONST_STR_LEN("auth.backend"), 468 CONST_STR_LEN("htpasswd"))) 469 ||(v=config_has_opt_and_value(srv,CONST_STR_LEN("auth.backend"), 470 CONST_STR_LEN("plain")))) 471 config_warn_authn_module(srv, CONST_STR_LEN("file"), v); 472 } 473 if (append_mod_authn_ldap) { 474 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER) 475 if (config_has_opt_and_value(srv, CONST_STR_LEN("auth.backend"), 476 CONST_STR_LEN("ldap"))) 477 config_warn_authn_module(srv, CONST_STR_LEN("ldap"), "ldap"); 478 #endif 479 } 480 } 481 482 if (prepend_mod_auth) { 483 config_compat_module_prepend(srv, CONST_STR_LEN("mod_auth")); 484 } 485 486 if (prepend_mod_vhostdb & 1) { 487 config_compat_module_prepend(srv, CONST_STR_LEN("mod_vhostdb")); 488 } 489 } 490 491 static void config_deprecate_module_compress (server *srv) { 492 int mod_compress_idx = -1; 493 int mod_deflate_idx = -1; 494 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 495 buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value; 496 if (buffer_eq_slen(m, CONST_STR_LEN("mod_compress"))) 497 mod_compress_idx = (int)i; 498 else if (buffer_eq_slen(m, CONST_STR_LEN("mod_deflate"))) 499 mod_deflate_idx = (int)i; 500 } 501 if (mod_compress_idx < 0) return; 502 503 int has_compress_directive = 0; 504 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 505 const data_config *config = 506 (data_config const *)srv->config_context->data[i]; 507 for (uint32_t j = 0; j < config->value->used; ++j) { 508 buffer *k = &config->value->data[j]->key; 509 if (0 == strncmp(k->ptr, "compress.", sizeof("compress.")-1)) { 510 has_compress_directive = 1; 511 break; 512 } 513 } 514 if (has_compress_directive) { 515 log_error(srv->errh, __FILE__, __LINE__, 516 "Warning: \"mod_compress\" is DEPRECATED and has been replaced " 517 "with \"mod_deflate\". A future release of lighttpd 1.4.x will " 518 "not contain mod_compress and lighttpd may fail to start up"); 519 break; 520 } 521 } 522 523 if (mod_deflate_idx >= 0 || !has_compress_directive) { 524 /* create new modules value list without mod_compress */ 525 array *a = array_init(srv->srvconf.modules->used-1); 526 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 527 buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value; 528 if (buffer_eq_slen(m, CONST_STR_LEN("mod_compress"))) 529 continue; 530 array_insert_value(a, BUF_PTR_LEN(m)); 531 } 532 array_free(srv->srvconf.modules); 533 srv->srvconf.modules = a; 534 } 535 else { 536 /* replace "mod_compress" value with "mod_deflate" value */ 537 buffer *m = &((data_string *)srv->srvconf.modules->data[mod_compress_idx])->value; 538 buffer_copy_string_len(m, CONST_STR_LEN("mod_deflate")); 539 } 540 } 541 542 static int config_http_parseopts (server *srv, const array *a) { 543 unsigned short int opts = srv->srvconf.http_url_normalize; 544 unsigned short int decode_2f = 1; 545 int rc = 1; 546 for (size_t i = 0; i < a->used; ++i) { 547 const data_string * const ds = (const data_string *)a->data[i]; 548 const buffer *k = &ds->key; 549 unsigned short int opt; 550 int val = config_plugin_value_tobool((data_unset *)ds, 2); 551 if (2 == val) { 552 log_error(srv->errh, __FILE__, __LINE__, 553 "unrecognized value for server.http-parseopts: " 554 "%s => %s (expect \"[enable|disable]\")", k->ptr, ds->value.ptr); 555 rc = 0; 556 } 557 if (buffer_eq_slen(k, CONST_STR_LEN("url-normalize"))) 558 opt = HTTP_PARSEOPT_URL_NORMALIZE; 559 else if (buffer_eq_slen(k, CONST_STR_LEN("url-normalize-unreserved"))) 560 opt = HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED; 561 else if (buffer_eq_slen(k, CONST_STR_LEN("url-normalize-required"))) 562 opt = HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED; 563 else if (buffer_eq_slen(k, CONST_STR_LEN("url-ctrls-reject"))) 564 opt = HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT; 565 else if (buffer_eq_slen(k, CONST_STR_LEN("url-path-backslash-trans"))) 566 opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS; 567 else if (buffer_eq_slen(k, CONST_STR_LEN("url-path-2f-decode"))) 568 opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE; 569 else if (buffer_eq_slen(k, CONST_STR_LEN("url-path-2f-reject"))) 570 opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT; 571 else if (buffer_eq_slen(k, CONST_STR_LEN("url-path-dotseg-remove"))) 572 opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE; 573 else if (buffer_eq_slen(k, CONST_STR_LEN("url-path-dotseg-reject"))) 574 opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT; 575 else if (buffer_eq_slen(k, CONST_STR_LEN("url-query-20-plus"))) 576 opt = HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS; 577 else if (buffer_eq_slen(k, CONST_STR_LEN("header-strict"))) { 578 srv->srvconf.http_header_strict = val; 579 continue; 580 } 581 else if (buffer_eq_slen(k, CONST_STR_LEN("host-strict"))) { 582 srv->srvconf.http_host_strict = val; 583 continue; 584 } 585 else if (buffer_eq_slen(k, CONST_STR_LEN("host-normalize"))) { 586 srv->srvconf.http_host_normalize = val; 587 continue; 588 } 589 else if (buffer_eq_slen(k, CONST_STR_LEN("method-get-body"))) { 590 srv->srvconf.http_method_get_body = val; 591 continue; 592 } 593 else { 594 log_error(srv->errh, __FILE__, __LINE__, 595 "unrecognized key for server.http-parseopts: %s", k->ptr); 596 rc = 0; 597 continue; 598 } 599 if (val) 600 opts |= opt; 601 else { 602 opts &= ~opt; 603 if (opt == HTTP_PARSEOPT_URL_NORMALIZE) { 604 opts = 0; 605 break; 606 } 607 if (opt == HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE) { 608 decode_2f = 0; 609 } 610 } 611 } 612 if (opts != 0) { 613 opts |= HTTP_PARSEOPT_URL_NORMALIZE; 614 if ((opts & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE 615 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)) 616 == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE 617 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)) { 618 log_error(srv->errh, __FILE__, __LINE__, 619 "conflicting options in server.http-parseopts:" 620 "url-path-2f-decode, url-path-2f-reject"); 621 rc = 0; 622 } 623 if ((opts & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE 624 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT)) 625 == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE 626 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT)) { 627 log_error(srv->errh, __FILE__, __LINE__, 628 "conflicting options in server.http-parseopts:" 629 "url-path-dotseg-remove, url-path-dotseg-reject"); 630 rc = 0; 631 } 632 if (!(opts & (HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED 633 |HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED))) { 634 opts |= HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED; 635 if (decode_2f 636 && !(opts & HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)) 637 opts |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE; 638 } 639 } 640 srv->srvconf.http_url_normalize = opts; 641 return rc; 642 } 643 644 static int config_insert_srvconf(server *srv) { 645 static const config_plugin_keys_t cpk[] = { 646 { CONST_STR_LEN("server.modules"), 647 T_CONFIG_ARRAY_VLIST, 648 T_CONFIG_SCOPE_SERVER } 649 ,{ CONST_STR_LEN("server.compat-module-load"), 650 T_CONFIG_BOOL, 651 T_CONFIG_SCOPE_SERVER } 652 ,{ CONST_STR_LEN("server.systemd-socket-activation"), 653 T_CONFIG_BOOL, 654 T_CONFIG_SCOPE_SERVER } 655 ,{ CONST_STR_LEN("server.port"), 656 T_CONFIG_SHORT, 657 T_CONFIG_SCOPE_SERVER } 658 ,{ CONST_STR_LEN("server.bind"), 659 T_CONFIG_STRING, 660 T_CONFIG_SCOPE_SERVER } 661 ,{ CONST_STR_LEN("server.network-backend"), 662 T_CONFIG_STRING, 663 T_CONFIG_SCOPE_SERVER } 664 ,{ CONST_STR_LEN("server.chroot"), 665 T_CONFIG_STRING, 666 T_CONFIG_SCOPE_SERVER } 667 ,{ CONST_STR_LEN("server.username"), 668 T_CONFIG_STRING, 669 T_CONFIG_SCOPE_SERVER } 670 ,{ CONST_STR_LEN("server.groupname"), 671 T_CONFIG_STRING, 672 T_CONFIG_SCOPE_SERVER } 673 ,{ CONST_STR_LEN("server.errorlog-placeholder-moved-to-config-insert"), 674 T_CONFIG_STRING, 675 T_CONFIG_SCOPE_SERVER } 676 ,{ CONST_STR_LEN("server.breakagelog-placeholder-moved-to-config-insert"), 677 T_CONFIG_STRING, 678 T_CONFIG_SCOPE_SERVER } 679 ,{ CONST_STR_LEN("server.errorlog-use-syslog"), 680 T_CONFIG_BOOL, 681 T_CONFIG_SCOPE_SERVER } 682 ,{ CONST_STR_LEN("server.syslog-facility"), 683 T_CONFIG_STRING, 684 T_CONFIG_SCOPE_SERVER } 685 ,{ CONST_STR_LEN("server.core-files"), 686 T_CONFIG_BOOL, 687 T_CONFIG_SCOPE_SERVER } 688 ,{ CONST_STR_LEN("server.event-handler"), 689 T_CONFIG_STRING, 690 T_CONFIG_SCOPE_SERVER } 691 ,{ CONST_STR_LEN("server.pid-file"), 692 T_CONFIG_STRING, 693 T_CONFIG_SCOPE_SERVER } 694 ,{ CONST_STR_LEN("server.max-worker"), 695 T_CONFIG_SHORT, 696 T_CONFIG_SCOPE_SERVER } 697 ,{ CONST_STR_LEN("server.max-fds"), 698 T_CONFIG_SHORT, 699 T_CONFIG_SCOPE_SERVER } 700 ,{ CONST_STR_LEN("server.max-connections"), 701 T_CONFIG_SHORT, 702 T_CONFIG_SCOPE_SERVER } 703 ,{ CONST_STR_LEN("server.max-request-field-size"), 704 T_CONFIG_INT, 705 T_CONFIG_SCOPE_SERVER } 706 ,{ CONST_STR_LEN("server.chunkqueue-chunk-sz"), 707 T_CONFIG_INT, 708 T_CONFIG_SCOPE_SERVER } 709 ,{ CONST_STR_LEN("server.upload-temp-file-size"), 710 T_CONFIG_INT, 711 T_CONFIG_SCOPE_SERVER } 712 ,{ CONST_STR_LEN("server.upload-dirs"), 713 T_CONFIG_ARRAY_VLIST, 714 T_CONFIG_SCOPE_SERVER } 715 ,{ CONST_STR_LEN("server.http-parseopts"), 716 T_CONFIG_ARRAY_KVSTRING, 717 T_CONFIG_SCOPE_SERVER } 718 ,{ CONST_STR_LEN("server.http-parseopt-header-strict"), 719 T_CONFIG_BOOL, 720 T_CONFIG_SCOPE_SERVER } 721 ,{ CONST_STR_LEN("server.http-parseopt-host-strict"), 722 T_CONFIG_BOOL, 723 T_CONFIG_SCOPE_SERVER } 724 ,{ CONST_STR_LEN("server.http-parseopt-host-normalize"), 725 T_CONFIG_BOOL, 726 T_CONFIG_SCOPE_SERVER } 727 ,{ CONST_STR_LEN("server.reject-expect-100-with-417"), /*(ignored)*/ 728 T_CONFIG_BOOL, 729 T_CONFIG_SCOPE_SERVER } 730 ,{ CONST_STR_LEN("server.stat-cache-engine"), 731 T_CONFIG_STRING, 732 T_CONFIG_SCOPE_SERVER } 733 ,{ CONST_STR_LEN("mimetype.xattr-name"), 734 T_CONFIG_STRING, 735 T_CONFIG_SCOPE_SERVER } 736 ,{ CONST_STR_LEN("ssl.engine"), 737 T_CONFIG_BOOL, 738 T_CONFIG_SCOPE_SOCKET } 739 ,{ CONST_STR_LEN("debug.log-request-header-on-error"), 740 T_CONFIG_BOOL, 741 T_CONFIG_SCOPE_SERVER } 742 ,{ CONST_STR_LEN("server.feature-flags"), 743 T_CONFIG_ARRAY_KVANY, 744 T_CONFIG_SCOPE_SERVER } 745 ,{ NULL, 0, 746 T_CONFIG_UNSET, 747 T_CONFIG_SCOPE_UNSET } 748 }; 749 750 srv->srvconf.h2proto = 2; /* enable HTTP/2 and h2c by default */ 751 752 int rc = 0; 753 plugin_data_base srvplug; 754 memset(&srvplug, 0, sizeof(srvplug)); 755 plugin_data_base * const p = &srvplug; 756 if (!config_plugin_values_init(srv, p, cpk, "global")) 757 return HANDLER_ERROR; 758 759 int ssl_enabled = 0; /*(directive checked here only to set default port)*/ 760 761 /* process and validate T_CONFIG_SCOPE_SERVER config directives */ 762 if (p->cvlist[0].v.u2[1]) { 763 config_plugin_value_t *cpv = p->cvlist + p->cvlist[0].v.u2[0]; 764 for (; -1 != cpv->k_id; ++cpv) { 765 switch (cpv->k_id) { 766 case 0: /* server.modules */ 767 array_copy_array(srv->srvconf.modules, cpv->v.a); 768 break; 769 case 1: /* server.compat-module-load */ 770 srv->srvconf.compat_module_load = (unsigned short)cpv->v.u; 771 break; 772 case 2: /* server.systemd-socket-activation */ 773 srv->srvconf.systemd_socket_activation=(unsigned short)cpv->v.u; 774 break; 775 case 3: /* server.port */ 776 srv->srvconf.port = cpv->v.shrt; 777 break; 778 case 4: /* server.bind */ 779 if (!buffer_is_blank(cpv->v.b)) 780 srv->srvconf.bindhost = cpv->v.b; 781 break; 782 case 5: /* server.network-backend */ 783 if (!buffer_is_blank(cpv->v.b)) 784 srv->srvconf.network_backend = cpv->v.b; 785 break; 786 case 6: /* server.chroot */ 787 if (!buffer_is_blank(cpv->v.b)) 788 srv->srvconf.changeroot = cpv->v.b; 789 break; 790 case 7: /* server.username */ 791 if (!buffer_is_blank(cpv->v.b)) 792 srv->srvconf.username = cpv->v.b; 793 break; 794 case 8: /* server.groupname */ 795 if (!buffer_is_blank(cpv->v.b)) 796 srv->srvconf.groupname = cpv->v.b; 797 break; 798 case 9: /* server.errorlog */ /* moved to config_insert() */ 799 /*srv->srvconf.errorlog_file = cpv->v.b;*/ 800 break; 801 case 10:/* server.breakagelog */ /* moved to config_insert() */ 802 /*srv->srvconf.breakagelog_file = cpv->v.b;*/ 803 break; 804 case 11:/* server.errorlog-use-syslog */ 805 srv->srvconf.errorlog_use_syslog = (unsigned short)cpv->v.u; 806 break; 807 case 12:/* server.syslog-facility */ 808 if (!buffer_is_blank(cpv->v.b)) 809 srv->srvconf.syslog_facility = cpv->v.b; 810 break; 811 case 13:/* server.core-files */ 812 srv->srvconf.enable_cores = (unsigned short)cpv->v.u; 813 break; 814 case 14:/* server.event-handler */ 815 srv->srvconf.event_handler = cpv->v.b->ptr; 816 break; 817 case 15:/* server.pid-file */ 818 if (!buffer_is_blank(cpv->v.b)) 819 *(const buffer **)&srv->srvconf.pid_file = cpv->v.b; 820 break; 821 case 16:/* server.max-worker */ 822 srv->srvconf.max_worker = (unsigned short)cpv->v.u; 823 break; 824 case 17:/* server.max-fds */ 825 srv->srvconf.max_fds = (unsigned short)cpv->v.u; 826 break; 827 case 18:/* server.max-connections */ 828 srv->srvconf.max_conns = (unsigned short)cpv->v.u; 829 break; 830 case 19:/* server.max-request-field-size */ 831 srv->srvconf.max_request_field_size = cpv->v.u; 832 break; 833 case 20:/* server.chunkqueue-chunk-sz */ 834 chunkqueue_set_chunk_size(cpv->v.u); 835 break; 836 case 21:/* server.upload-temp-file-size */ 837 srv->srvconf.upload_temp_file_size = cpv->v.u; 838 break; 839 case 22:/* server.upload-dirs */ 840 array_copy_array(srv->srvconf.upload_tempdirs, cpv->v.a); 841 break; 842 case 23:/* server.http-parseopts */ 843 if (!config_http_parseopts(srv, cpv->v.a)) 844 rc = HANDLER_ERROR; 845 break; 846 case 24:/* server.http-parseopt-header-strict */ 847 srv->srvconf.http_header_strict = (0 != cpv->v.u); 848 break; 849 case 25:/* server.http-parseopt-host-strict */ 850 srv->srvconf.http_host_strict = (0 != cpv->v.u); 851 break; 852 case 26:/* server.http-parseopt-host-normalize */ 853 srv->srvconf.http_host_normalize = (0 != cpv->v.u); 854 break; 855 case 27:/* server.reject-expect-100-with-417 *//*(ignored)*/ 856 break; 857 case 28:/* server.stat-cache-engine */ 858 if (0 != stat_cache_choose_engine(cpv->v.b, srv->errh)) 859 rc = HANDLER_ERROR; 860 break; 861 case 29:/* mimetype.xattr-name */ 862 stat_cache_xattrname(cpv->v.b->ptr); 863 break; 864 case 30:/* ssl.engine */ 865 ssl_enabled = (0 != cpv->v.u); 866 #if !defined(USE_OPENSSL_CRYPTO) \ 867 && !defined(USE_MBEDTLS_CRYPTO) \ 868 && !defined(USE_NSS_CRYPTO) \ 869 && !defined(USE_GNUTLS_CRYPTO) \ 870 && !defined(USE_WOLFSSL_CRYPTO) 871 if (ssl_enabled) { 872 log_error(srv->errh, __FILE__, __LINE__, 873 "ssl support is missing; " 874 "recompile with e.g. --with-openssl"); 875 rc = HANDLER_ERROR; 876 break; 877 } 878 #endif 879 break; 880 case 31:/* debug.log-request-header-on-error */ 881 srv->srvconf.log_request_header_on_error = (0 != cpv->v.u); 882 break; 883 case 32:/* server.feature-flags */ 884 srv->srvconf.feature_flags = cpv->v.a; 885 srv->srvconf.h2proto = 886 config_plugin_value_tobool( 887 array_get_element_klen(cpv->v.a, 888 CONST_STR_LEN("server.h2proto")), 1); 889 if (srv->srvconf.h2proto) 890 srv->srvconf.h2proto += 891 config_plugin_value_tobool( 892 array_get_element_klen(cpv->v.a, 893 CONST_STR_LEN("server.h2c")), 1); 894 srv->srvconf.absolute_dir_redirect = 895 config_plugin_value_tobool( 896 array_get_element_klen(cpv->v.a, 897 CONST_STR_LEN("server.absolute-dir-redirect")), 0); 898 break; 899 default:/* should not happen */ 900 break; 901 } 902 } 903 } 904 905 if (0 == srv->srvconf.port) 906 srv->srvconf.port = ssl_enabled ? 443 : 80; 907 908 config_check_module_duplicates(srv); 909 910 if (srv->srvconf.compat_module_load) 911 config_compat_module_load(srv); 912 913 config_deprecate_module_compress(srv); 914 915 if (srv->srvconf.http_url_normalize) 916 config_burl_normalize_cond(srv); 917 918 if (!config_pcre_keyvalue(srv)) 919 rc = HANDLER_ERROR; 920 921 free(srvplug.cvlist); 922 return rc; 923 } 924 925 static int config_insert(server *srv) { 926 static const config_plugin_keys_t cpk[] = { 927 { CONST_STR_LEN("server.document-root"), 928 T_CONFIG_STRING, 929 T_CONFIG_SCOPE_CONNECTION } 930 ,{ CONST_STR_LEN("server.name"), 931 T_CONFIG_STRING, 932 T_CONFIG_SCOPE_CONNECTION } 933 ,{ CONST_STR_LEN("server.tag"), 934 T_CONFIG_STRING, 935 T_CONFIG_SCOPE_CONNECTION } 936 ,{ CONST_STR_LEN("server.max-request-size"), 937 T_CONFIG_INT, 938 T_CONFIG_SCOPE_CONNECTION } 939 ,{ CONST_STR_LEN("server.max-keep-alive-requests"), 940 T_CONFIG_SHORT, 941 T_CONFIG_SCOPE_CONNECTION } 942 ,{ CONST_STR_LEN("server.max-keep-alive-idle"), 943 T_CONFIG_SHORT, 944 T_CONFIG_SCOPE_CONNECTION } 945 ,{ CONST_STR_LEN("server.max-read-idle"), 946 T_CONFIG_SHORT, 947 T_CONFIG_SCOPE_CONNECTION } 948 ,{ CONST_STR_LEN("server.max-write-idle"), 949 T_CONFIG_SHORT, 950 T_CONFIG_SCOPE_CONNECTION } 951 ,{ CONST_STR_LEN("server.errorfile-prefix"), 952 T_CONFIG_STRING, 953 T_CONFIG_SCOPE_CONNECTION } 954 ,{ CONST_STR_LEN("server.error-handler"), 955 T_CONFIG_STRING, 956 T_CONFIG_SCOPE_CONNECTION } 957 ,{ CONST_STR_LEN("server.error-handler-404"), 958 T_CONFIG_STRING, 959 T_CONFIG_SCOPE_CONNECTION } 960 ,{ CONST_STR_LEN("server.error-intercept"), 961 T_CONFIG_BOOL, 962 T_CONFIG_SCOPE_CONNECTION } 963 ,{ CONST_STR_LEN("server.force-lowercase-filenames"), 964 T_CONFIG_BOOL, 965 T_CONFIG_SCOPE_CONNECTION } 966 ,{ CONST_STR_LEN("server.follow-symlink"), 967 T_CONFIG_BOOL, 968 T_CONFIG_SCOPE_CONNECTION } 969 ,{ CONST_STR_LEN("server.protocol-http11"), 970 T_CONFIG_BOOL, 971 T_CONFIG_SCOPE_CONNECTION } 972 ,{ CONST_STR_LEN("server.range-requests"), 973 T_CONFIG_BOOL, 974 T_CONFIG_SCOPE_CONNECTION } 975 ,{ CONST_STR_LEN("server.stream-request-body"), 976 T_CONFIG_SHORT, 977 T_CONFIG_SCOPE_CONNECTION } 978 ,{ CONST_STR_LEN("server.stream-response-body"), 979 T_CONFIG_SHORT, 980 T_CONFIG_SCOPE_CONNECTION } 981 ,{ CONST_STR_LEN("server.kbytes-per-second"), 982 T_CONFIG_SHORT, 983 T_CONFIG_SCOPE_CONNECTION } 984 ,{ CONST_STR_LEN("connection.kbytes-per-second"), 985 T_CONFIG_SHORT, 986 T_CONFIG_SCOPE_CONNECTION } 987 ,{ CONST_STR_LEN("mimetype.assign"), 988 T_CONFIG_ARRAY_KVSTRING, 989 T_CONFIG_SCOPE_CONNECTION } 990 ,{ CONST_STR_LEN("mimetype.use-xattr"), 991 T_CONFIG_BOOL, 992 T_CONFIG_SCOPE_CONNECTION } 993 ,{ CONST_STR_LEN("etag.use-inode"), 994 T_CONFIG_BOOL, 995 T_CONFIG_SCOPE_CONNECTION } 996 ,{ CONST_STR_LEN("etag.use-mtime"), 997 T_CONFIG_BOOL, 998 T_CONFIG_SCOPE_CONNECTION } 999 ,{ CONST_STR_LEN("etag.use-size"), 1000 T_CONFIG_BOOL, 1001 T_CONFIG_SCOPE_CONNECTION } 1002 ,{ CONST_STR_LEN("debug.log-condition-handling"), 1003 T_CONFIG_BOOL, 1004 T_CONFIG_SCOPE_CONNECTION } 1005 ,{ CONST_STR_LEN("debug.log-file-not-found"), 1006 T_CONFIG_BOOL, 1007 T_CONFIG_SCOPE_CONNECTION } 1008 ,{ CONST_STR_LEN("debug.log-request-handling"), 1009 T_CONFIG_BOOL, 1010 T_CONFIG_SCOPE_CONNECTION } 1011 ,{ CONST_STR_LEN("debug.log-request-header"), 1012 T_CONFIG_BOOL, 1013 T_CONFIG_SCOPE_CONNECTION } 1014 ,{ CONST_STR_LEN("debug.log-response-header"), 1015 T_CONFIG_BOOL, 1016 T_CONFIG_SCOPE_CONNECTION } 1017 ,{ CONST_STR_LEN("debug.log-timeouts"), 1018 T_CONFIG_BOOL, 1019 T_CONFIG_SCOPE_CONNECTION } 1020 ,{ CONST_STR_LEN("debug.log-state-handling"), 1021 T_CONFIG_BOOL, 1022 T_CONFIG_SCOPE_CONNECTION } 1023 ,{ CONST_STR_LEN("server.errorlog"), 1024 T_CONFIG_STRING, 1025 T_CONFIG_SCOPE_CONNECTION } 1026 ,{ CONST_STR_LEN("server.breakagelog"), 1027 T_CONFIG_STRING, 1028 T_CONFIG_SCOPE_CONNECTION } 1029 ,{ NULL, 0, 1030 T_CONFIG_UNSET, 1031 T_CONFIG_SCOPE_UNSET } 1032 }; 1033 1034 int rc = 0; 1035 config_data_base * const p = calloc(1, sizeof(config_data_base)); 1036 force_assert(p); 1037 srv->config_data_base = p; 1038 1039 if (!config_plugin_values_init(srv, p, cpk, "base")) 1040 return HANDLER_ERROR; 1041 1042 /* process and validate T_CONFIG_SCOPE_CONNECTION config directives 1043 * (init i to 0 if global context; to 1 to skip empty global context) */ 1044 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { 1045 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 1046 for (; -1 != cpv->k_id; ++cpv) { 1047 switch (cpv->k_id) { 1048 case 0: /* server.document-root */ 1049 break; 1050 case 1: /* server.name */ 1051 if (buffer_is_blank(cpv->v.b)) 1052 cpv->v.b = NULL; 1053 break; 1054 case 2: /* server.tag */ 1055 if (!buffer_is_blank(cpv->v.b)) { 1056 buffer *b; 1057 *(const buffer **)&b = cpv->v.b; 1058 for (char *t=strchr(b->ptr,'\n'); t; t=strchr(t+2,'\n')) { 1059 /* not expecting admin to define multi-line server.tag, 1060 * but ensure server_tag has proper header continuation, 1061 * if needed */ 1062 if (t[1] == ' ' || t[1] == '\t') continue; 1063 off_t off = t - b->ptr; 1064 size_t len = buffer_clen(b); 1065 buffer_string_prepare_append(b, 1); 1066 t = b->ptr+off; 1067 memmove(t+2, t+1, len - off - 1); 1068 t[1] = ' '; 1069 buffer_commit(b, 1); 1070 } 1071 char *t = b->ptr; /*(make empty if tag is whitespace-only)*/ 1072 while (*t==' ' || *t=='\t' || *t=='\r' || *t=='\n') ++t; 1073 if (*t == '\0') buffer_truncate(b, 0); 1074 if (buffer_is_blank(b) && 0 != i) 1075 cpv->v.b = NULL; 1076 else { /* prep for use by h2.c:h2_send_headers() */ 1077 buffer_string_prepare_append(b, 6); 1078 memcpy(b->ptr+buffer_clen(b)+1, "server", 6); 1079 } 1080 } 1081 else if (0 != i) 1082 cpv->v.b = NULL; 1083 break; 1084 case 3: /* server.max-request-size */ 1085 case 4: /* server.max-keep-alive-requests */ 1086 case 5: /* server.max-keep-alive-idle */ 1087 case 6: /* server.max-read-idle */ 1088 case 7: /* server.max-write-idle */ 1089 break; 1090 case 8: /* server.errorfile-prefix */ 1091 case 9: /* server.error-handler */ 1092 case 10:/* server.error-handler-404 */ 1093 if (buffer_is_blank(cpv->v.b)) 1094 cpv->v.b = NULL; 1095 break; 1096 case 11:/* server.error-intercept */ 1097 case 12:/* server.force-lowercase-filenames */ 1098 break; 1099 case 13:/* server.follow-symlink */ 1100 #ifndef HAVE_LSTAT 1101 if (0 == cpv->v.u) 1102 log_error(srv->errh, __FILE__, __LINE__, 1103 "Your system lacks lstat(). " 1104 "We can not differ symlinks from files. " 1105 "Please remove server.follow-symlinks from your config."); 1106 #endif 1107 break; 1108 case 14:/* server.protocol-http11 */ 1109 case 15:/* server.range-requests */ 1110 break; 1111 case 16:/* server.stream-request-body */ 1112 if (cpv->v.shrt & FDEVENT_STREAM_REQUEST_BUFMIN) 1113 cpv->v.shrt |=FDEVENT_STREAM_REQUEST; 1114 break; 1115 case 17:/* server.stream-response-body */ 1116 if (cpv->v.shrt & FDEVENT_STREAM_RESPONSE_BUFMIN) 1117 cpv->v.shrt |=FDEVENT_STREAM_RESPONSE; 1118 break; 1119 case 18:{/*server.kbytes-per-second */ 1120 off_t * const cnt = malloc(2*sizeof(off_t)); 1121 force_assert(cnt); 1122 cnt[0] = 0; 1123 cnt[1] = (off_t)cpv->v.shrt << 10; 1124 cpv->v.v = cnt; 1125 cpv->vtype = T_CONFIG_LOCAL; 1126 break; 1127 } 1128 case 19:/* connection.kbytes-per-second */ 1129 case 20:/* mimetype.assign */ 1130 case 21:/* mimetype.use-xattr */ 1131 case 22:/* etag.use-inode */ 1132 case 23:/* etag.use-mtime */ 1133 case 24:/* etag.use-size */ 1134 case 25:/* debug.log-condition-handling */ 1135 case 26:/* debug.log-file-not-found */ 1136 case 27:/* debug.log-request-handling */ 1137 case 28:/* debug.log-request-header */ 1138 case 29:/* debug.log-response-header */ 1139 case 30:/* debug.log-timeouts */ 1140 case 31:/* debug.log-state-handling */ 1141 case 32:/* server.errorlog *//*must match config_log_error_open*/ 1142 case 33:/* server.breakagelog */ /* match config_log_error_open*/ 1143 break; 1144 default:/* should not happen */ 1145 break; 1146 } 1147 } 1148 } 1149 1150 p->defaults.errh = srv->errh; 1151 p->defaults.max_keep_alive_requests = 1000; 1152 p->defaults.max_keep_alive_idle = 5; 1153 p->defaults.max_read_idle = 60; 1154 p->defaults.max_write_idle = 360; 1155 p->defaults.follow_symlink = 1; 1156 p->defaults.allow_http11 = 1; 1157 p->defaults.etag_flags = ETAG_USE_INODE | ETAG_USE_MTIME | ETAG_USE_SIZE; 1158 p->defaults.range_requests = 1; 1159 /* use 2 to detect later if value is set by user config in global section */ 1160 p->defaults.force_lowercase_filenames = 2; 1161 1162 /*(global, but store in r->conf.http_parseopts)*/ 1163 p->defaults.http_parseopts = 1164 (srv->srvconf.http_header_strict ? HTTP_PARSEOPT_HEADER_STRICT :0) 1165 | (srv->srvconf.http_host_strict ? (HTTP_PARSEOPT_HOST_STRICT 1166 |HTTP_PARSEOPT_HOST_NORMALIZE) :0) 1167 | (srv->srvconf.http_host_normalize ? HTTP_PARSEOPT_HOST_NORMALIZE :0) 1168 | (srv->srvconf.http_method_get_body ? HTTP_PARSEOPT_METHOD_GET_BODY :0); 1169 p->defaults.http_parseopts |= srv->srvconf.http_url_normalize; 1170 p->defaults.mimetypes = &srv->srvconf.empty_array; /*(must not be NULL)*/ 1171 p->defaults.h2proto = srv->srvconf.h2proto; 1172 1173 /* initialize p->defaults from global config context */ 1174 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 1175 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 1176 if (-1 != cpv->k_id) 1177 config_merge_config(&p->defaults, cpv); 1178 } 1179 1180 /* (after processing config defaults) */ 1181 p->defaults.max_request_field_size = srv->srvconf.max_request_field_size; 1182 p->defaults.log_request_header_on_error = 1183 srv->srvconf.log_request_header_on_error; 1184 if (p->defaults.log_request_handling || p->defaults.log_request_header) 1185 p->defaults.log_request_header_on_error = 1; 1186 1187 request_config_set_defaults(&p->defaults); 1188 1189 return rc; 1190 } 1191 1192 int config_finalize(server *srv, const buffer *default_server_tag) { 1193 /* (call after plugins_call_set_defaults()) */ 1194 1195 config_data_base * const p = srv->config_data_base; 1196 1197 /* settings might be enabled during plugins_call_set_defaults() */ 1198 p->defaults.high_precision_timestamps = 1199 srv->srvconf.high_precision_timestamps; 1200 1201 /* configure default server_tag if not set 1202 * (if configured to blank, unset server_tag)*/ 1203 if (!p->defaults.server_tag) 1204 p->defaults.server_tag = default_server_tag; 1205 else if (buffer_is_blank(p->defaults.server_tag)) 1206 p->defaults.server_tag = NULL; 1207 1208 /* dump unused config keys */ 1209 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 1210 array *config = ((data_config *)srv->config_context->data[i])->value; 1211 for (uint32_t j = 0; config && j < config->used; ++j) { 1212 const buffer * const k = &config->data[j]->key; 1213 1214 /* all var.* is known as user defined variable */ 1215 if (strncmp(k->ptr, "var.", sizeof("var.") - 1) == 0) 1216 continue; 1217 1218 if (!array_get_element_klen(srv->srvconf.config_touched, 1219 BUF_PTR_LEN(k))) 1220 log_error(srv->errh, __FILE__, __LINE__, 1221 "WARNING: unknown config-key: %s (ignored)", k->ptr); 1222 } 1223 } 1224 1225 array_free(srv->srvconf.config_touched); 1226 srv->srvconf.config_touched = NULL; 1227 1228 if (srv->srvconf.config_unsupported || srv->srvconf.config_deprecated) { 1229 if (srv->srvconf.config_unsupported) 1230 log_error(srv->errh, __FILE__, __LINE__, 1231 "Configuration contains unsupported keys. Going down."); 1232 if (srv->srvconf.config_deprecated) 1233 log_error(srv->errh, __FILE__, __LINE__, 1234 "Configuration contains deprecated keys. Going down."); 1235 return 0; 1236 } 1237 1238 /* check if condition regex captures are used by modules (redirect,rewrite) 1239 * and convert back to regex if condition was simplified to non-regex by 1240 * configparser_simplify_regex() */ 1241 if (__builtin_expect( (srv->config_captures != 0), 0)) { 1242 for (uint32_t i = 1; i < srv->config_context->used; ++i) { 1243 data_config * const dc = 1244 (data_config *)srv->config_context->data[i]; 1245 if (__builtin_expect( (0 == dc->capture_idx), 1)) 1246 continue; 1247 switch (dc->cond) { 1248 case CONFIG_COND_EQ: 1249 case CONFIG_COND_PREFIX: 1250 case CONFIG_COND_SUFFIX: 1251 break; 1252 /*case CONFIG_COND_NE:*/ 1253 /*case CONFIG_COND_MATCH:*/ 1254 /*case CONFIG_COND_NOMATCH:*/ 1255 /*case CONFIG_COND_ELSE:*/ 1256 default: 1257 continue; 1258 } 1259 buffer * const b = &dc->string; 1260 if (dc->cond != CONFIG_COND_SUFFIX || b->ptr[0] == '.') { 1261 buffer_extend(b, 1); 1262 memmove(b->ptr+1, b->ptr, buffer_clen(b)-1); 1263 b->ptr[0] = (dc->cond == CONFIG_COND_SUFFIX) ? '\\' : '^'; 1264 } 1265 if (dc->cond != CONFIG_COND_PREFIX) 1266 buffer_append_char(b, '$'); 1267 dc->cond = CONFIG_COND_MATCH; 1268 /*(config_pcre_keyvalue())*/ 1269 const int pcre_jit = config_feature_bool(srv, "server.pcre_jit", 1); 1270 if (!data_config_pcre_compile(dc, pcre_jit, srv->errh)) 1271 return 0; 1272 } 1273 } 1274 1275 #ifdef HAVE_PCRE2_H 1276 for (uint32_t i = 1; i < srv->config_context->used; ++i) { 1277 data_config * const dc = 1278 (data_config *)srv->config_context->data[i]; 1279 if ((dc->cond == CONFIG_COND_MATCH || dc->cond == CONFIG_COND_NOMATCH) 1280 && 0 == dc->capture_idx) { 1281 if (__builtin_expect( (NULL == srv->match_data), 0)) { 1282 #if 0 1283 /* calculate max output vector size to save a few bytes; 1284 * currently using hard-coded ovec_max = 10 below 1285 * (increase in code size is probably more than bytes saved) */ 1286 uint32_t ovec_max = 0; 1287 for (uint32_t j = i; j < srv->config_context->used; ++j) { 1288 const data_config * const dc = 1289 (data_config *)srv->config_context->data[j]; 1290 if ((dc->cond == CONFIG_COND_MATCH 1291 || dc->cond == CONFIG_COND_NOMATCH) 1292 && 0 == dc->capture_idx) { 1293 uint32_t v; 1294 if (0==pcre2_pattern_info(dc->code, 1295 PCRE2_INFO_CAPTURECOUNT,&v)) { 1296 if (ovec_max < v) 1297 ovec_max = v; 1298 } 1299 } 1300 } 1301 #else 1302 uint32_t ovec_max = 10; 1303 #endif 1304 srv->match_data = pcre2_match_data_create(ovec_max, NULL); 1305 force_assert(srv->match_data); 1306 } 1307 dc->match_data = srv->match_data; 1308 } 1309 } 1310 #endif 1311 1312 return 1; 1313 } 1314 1315 1316 /* Save some bytes using buffer_append_string() in cold funcs to print config 1317 * (instead of buffer_append_string_len() w/ CONST_STR_LEN() on constant strs)*/ 1318 1319 static void config_print_by_type(const data_unset *du, buffer *b, int depth); 1320 1321 static void config_print_indent(buffer *b, int depth) { 1322 depth <<= 2; 1323 memset(buffer_extend(b, depth), ' ', depth); 1324 } 1325 1326 __attribute_pure__ 1327 static uint32_t config_print_array_max_klen(const array * const a) { 1328 uint32_t maxlen = 0; 1329 for (uint32_t i = 0; i < a->used; ++i) { 1330 uint32_t len = buffer_clen(&a->data[i]->key); 1331 if (maxlen < len) 1332 maxlen = len; 1333 } 1334 return maxlen; 1335 } 1336 1337 static void config_print_array(const array * const a, buffer * const b, int depth) { 1338 if (a->used <= 5 && (!a->used || buffer_is_unset(&a->data[0]->key))) { 1339 int oneline = 1; 1340 for (uint32_t i = 0; i < a->used; ++i) { 1341 data_unset *du = a->data[i]; 1342 if (du->type != TYPE_STRING && du->type != TYPE_INTEGER) { 1343 oneline = 0; 1344 break; 1345 } 1346 } 1347 if (oneline) { 1348 buffer_append_string(b, "("); 1349 for (uint32_t i = 0; i < a->used; ++i) { 1350 if (i != 0) 1351 buffer_append_string(b, ", "); 1352 config_print_by_type(a->data[i], b, depth + 1); 1353 } 1354 buffer_append_string(b, ")"); 1355 return; 1356 } 1357 } 1358 1359 const uint32_t maxlen = config_print_array_max_klen(a); 1360 buffer_append_string(b, "(\n"); 1361 for (uint32_t i = 0; i < a->used; ++i) { 1362 config_print_indent(b, depth + 1); 1363 data_unset *du = a->data[i]; 1364 if (!buffer_is_unset(&du->key)) { 1365 buffer_append_str3(b, CONST_STR_LEN("\""), 1366 BUF_PTR_LEN(&du->key), 1367 CONST_STR_LEN("\"")); 1368 int indent = (int)(maxlen - buffer_clen(&du->key)); 1369 if (indent > 0) 1370 memset(buffer_extend(b, indent), ' ', indent); 1371 buffer_append_string(b, " => "); 1372 } 1373 config_print_by_type(du, b, depth + 1); 1374 buffer_append_string(b, ",\n"); 1375 } 1376 config_print_indent(b, depth); 1377 buffer_append_string(b, ")"); 1378 } 1379 1380 static void config_print_config(const data_unset *d, buffer * const b, int depth) { 1381 data_config *dc = (data_config *)d; 1382 array *a = (array *)dc->value; 1383 1384 if (0 == dc->context_ndx) { 1385 buffer_append_string(b, "config {\n"); 1386 } 1387 else { 1388 if (dc->cond != CONFIG_COND_ELSE) { 1389 buffer_append_string(b, dc->comp_key); 1390 buffer_append_string(b, " "); 1391 } 1392 buffer_append_string(b, "{\n"); 1393 config_print_indent(b, depth + 1); 1394 buffer_append_string(b, "# block "); 1395 buffer_append_int(b, dc->context_ndx); 1396 buffer_append_string(b, "\n"); 1397 } 1398 ++depth; 1399 1400 const uint32_t maxlen = config_print_array_max_klen(a); 1401 for (uint32_t i = 0; i < a->used; ++i) { 1402 config_print_indent(b, depth); 1403 data_unset *du = a->data[i]; 1404 buffer_append_string_buffer(b, &du->key); 1405 int indent = (int)(maxlen - buffer_clen(&du->key)); 1406 if (indent > 0) 1407 memset(buffer_extend(b, indent), ' ', indent); 1408 buffer_append_string(b, " = "); 1409 config_print_by_type(du, b, depth); 1410 buffer_append_string(b, "\n"); 1411 } 1412 1413 buffer_append_string(b, "\n"); 1414 for (uint32_t i = 0; i < dc->children.used; ++i) { 1415 data_config *dcc = dc->children.data[i]; 1416 1417 /* only the 1st block of chaining */ 1418 if (NULL == dcc->prev) { 1419 buffer_append_string(b, "\n"); 1420 config_print_indent(b, depth); 1421 config_print_by_type((data_unset *) dcc, b, depth); 1422 buffer_append_string(b, "\n"); 1423 } 1424 } 1425 1426 --depth; 1427 config_print_indent(b, depth); 1428 buffer_append_string(b, "}"); 1429 if (0 != dc->context_ndx) { 1430 buffer_append_string(b, " # end of "); 1431 buffer_append_string(b, (dc->cond != CONFIG_COND_ELSE) 1432 ? dc->comp_key 1433 : "else"); 1434 } 1435 1436 if (dc->next) { 1437 buffer_append_string(b, "\n"); 1438 config_print_indent(b, depth); 1439 buffer_append_string(b, "else "); 1440 config_print_by_type((data_unset *)dc->next, b, depth); 1441 } 1442 } 1443 1444 static void config_print_string(const data_unset *du, buffer * const b) { 1445 /* print out the string as is, except prepend '"' with backslash */ 1446 const buffer * const vb = &((data_string *)du)->value; 1447 char *dst = buffer_string_prepare_append(b, buffer_clen(vb)*2); 1448 uint32_t n = 0; 1449 dst[n++] = '"'; 1450 if (vb->ptr) { 1451 for (const char *p = vb->ptr; *p; ++p) { 1452 if (*p == '"') 1453 dst[n++] = '\\'; 1454 dst[n++] = *p; 1455 } 1456 } 1457 dst[n++] = '"'; 1458 buffer_commit(b, n); 1459 } 1460 1461 __attribute_cold__ 1462 static void config_print_by_type(const data_unset * const du, buffer * const b, int depth) { 1463 switch (du->type) { 1464 case TYPE_STRING: 1465 config_print_string(du, b); 1466 break; 1467 case TYPE_INTEGER: 1468 buffer_append_int(b, ((data_integer *)du)->value); 1469 break; 1470 case TYPE_ARRAY: 1471 config_print_array(&((data_array *)du)->value, b, depth); 1472 break; 1473 case TYPE_CONFIG: 1474 config_print_config(du, b, depth); 1475 break; 1476 default: 1477 /*if (du->fn->print) du->fn->print(du, b, depth);*/ 1478 break; 1479 } 1480 } 1481 1482 void config_print(server *srv) { 1483 buffer_clear(srv->tmp_buf); 1484 data_unset *dc = srv->config_context->data[0]; 1485 config_print_by_type(dc, srv->tmp_buf, 0); 1486 } 1487 1488 void config_free(server *srv) { 1489 /*request_config_set_defaults(NULL);*//*(not necessary)*/ 1490 config_free_config(srv->config_data_base); 1491 1492 array_free(srv->config_context); 1493 array_free(srv->srvconf.config_touched); 1494 array_free(srv->srvconf.modules); 1495 array_free(srv->srvconf.upload_tempdirs); 1496 #ifdef HAVE_PCRE2_H 1497 if (NULL == srv->match_data) pcre2_match_data_free(srv->match_data); 1498 #endif 1499 } 1500 1501 void config_init(server *srv) { 1502 srv->config_context = array_init(16); 1503 srv->srvconf.config_touched = array_init(128); 1504 1505 srv->srvconf.port = 0; 1506 srv->srvconf.dont_daemonize = 0; 1507 srv->srvconf.preflight_check = 0; 1508 srv->srvconf.compat_module_load = 1; 1509 srv->srvconf.systemd_socket_activation = 0; 1510 1511 srv->srvconf.high_precision_timestamps = 0; 1512 srv->srvconf.max_request_field_size = 8192; 1513 1514 srv->srvconf.http_header_strict = 1; 1515 srv->srvconf.http_host_strict = 1; /*(implies http_host_normalize)*/ 1516 srv->srvconf.http_host_normalize = 0; 1517 srv->srvconf.http_url_normalize = 1518 HTTP_PARSEOPT_URL_NORMALIZE 1519 | HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED 1520 | HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT 1521 | HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE 1522 | HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE; 1523 1524 srv->srvconf.modules = array_init(16); 1525 srv->srvconf.modules_dir = LIBRARY_DIR; 1526 srv->srvconf.upload_tempdirs = array_init(2); 1527 } 1528 1529 /** 1530 * open the errorlog 1531 * 1532 * we have 4 possibilities: 1533 * - stderr (default) 1534 * - syslog 1535 * - logfile 1536 * - pipe 1537 * 1538 */ 1539 1540 static void config_log_error_open_syslog(server *srv, log_error_st *errh, const buffer *syslog_facility) { 1541 #ifdef HAVE_SYSLOG_H 1542 /*assert(errh->mode == FDLOG_FD);*/ 1543 /*assert(errh->fd == STDERR_FILENO);*/ 1544 errh->mode = FDLOG_SYSLOG; 1545 errh->fd = -1; 1546 /* perhaps someone wants to use syslog() */ 1547 int facility = -1; 1548 if (syslog_facility) { 1549 static const struct facility_name_st { 1550 const char *name; 1551 int val; 1552 } facility_names[] = { 1553 { "auth", LOG_AUTH } 1554 #ifdef LOG_AUTHPRIV 1555 ,{ "authpriv", LOG_AUTHPRIV } 1556 #endif 1557 #ifdef LOG_CRON 1558 ,{ "cron", LOG_CRON } 1559 #endif 1560 ,{ "daemon", LOG_DAEMON } 1561 #ifdef LOG_FTP 1562 ,{ "ftp", LOG_FTP } 1563 #endif 1564 #ifdef LOG_KERN 1565 ,{ "kern", LOG_KERN } 1566 #endif 1567 #ifdef LOG_LPR 1568 ,{ "lpr", LOG_LPR } 1569 #endif 1570 #ifdef LOG_MAIL 1571 ,{ "mail", LOG_MAIL } 1572 #endif 1573 #ifdef LOG_NEWS 1574 ,{ "news", LOG_NEWS } 1575 #endif 1576 ,{ "security", LOG_AUTH } /* DEPRECATED */ 1577 #ifdef LOG_SYSLOG 1578 ,{ "syslog", LOG_SYSLOG } 1579 #endif 1580 #ifdef LOG_USER 1581 ,{ "user", LOG_USER } 1582 #endif 1583 #ifdef LOG_UUCP 1584 ,{ "uucp", LOG_UUCP } 1585 #endif 1586 ,{ "local0", LOG_LOCAL0 } 1587 ,{ "local1", LOG_LOCAL1 } 1588 ,{ "local2", LOG_LOCAL2 } 1589 ,{ "local3", LOG_LOCAL3 } 1590 ,{ "local4", LOG_LOCAL4 } 1591 ,{ "local5", LOG_LOCAL5 } 1592 ,{ "local6", LOG_LOCAL6 } 1593 ,{ "local7", LOG_LOCAL7 } 1594 }; 1595 for (unsigned int i = 0; i < sizeof(facility_names)/sizeof(facility_names[0]); ++i) { 1596 const struct facility_name_st *f = facility_names+i; 1597 if (0 == strcmp(syslog_facility->ptr, f->name)) { 1598 facility = f->val; 1599 break; 1600 } 1601 } 1602 if (-1 == facility) { 1603 log_error(srv->errh, __FILE__, __LINE__, 1604 "unrecognized server.syslog-facility: \"%s\"; " 1605 "defaulting to \"daemon\" facility", 1606 syslog_facility->ptr); 1607 } 1608 } 1609 openlog("lighttpd", LOG_CONS|LOG_PID, -1==facility ? LOG_DAEMON : facility); 1610 #endif 1611 } 1612 1613 int config_log_error_open(server *srv) { 1614 /* logs are opened after preflight check (srv->srvconf.preflight_check) 1615 * and after dropping privileges instead of being opened during config 1616 * processing */ 1617 #ifdef __clang_analyzer__ 1618 force_assert(srv->errh); 1619 #endif 1620 1621 config_data_base * const p = srv->config_data_base; 1622 log_error_st *serrh = NULL; 1623 1624 /* future: might be slightly faster to have allocated array of open files 1625 * rather than walking config, but only might matter with many directives */ 1626 /* (init i to 0 if global context; to 1 to skip empty global context) */ 1627 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { 1628 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 1629 for (; -1 != cpv->k_id; ++cpv) { 1630 const char *fn = NULL; 1631 log_error_st *errh = NULL; 1632 switch (cpv->k_id) { 1633 /* NB: these indexes are repeated below switch() block 1634 * and all must stay in sync with configfile.c */ 1635 case 32:/* server.errorlog */ 1636 if (0 == i) { 1637 if (srv->srvconf.errorlog_use_syslog) continue; 1638 errh = srv->errh; 1639 } 1640 __attribute_fallthrough__ 1641 case 33:/* server.breakagelog */ 1642 if (!buffer_is_blank(cpv->v.b)) fn = cpv->v.b->ptr; 1643 break; 1644 default: 1645 break; 1646 } 1647 1648 if (NULL == fn) continue; 1649 1650 fdlog_st * const fdlog = fdlog_open(fn); 1651 if (NULL == fdlog) { 1652 log_perror(srv->errh, __FILE__, __LINE__, 1653 "opening errorlog '%s' failed", fn); 1654 return -1; 1655 } 1656 1657 if (errh) { 1658 /*(logfiles are opened early in setup; this function is called 1659 * prior to set_defaults hook, and modules should not save a 1660 * pointer to srv->errh until set_defaults hook or later)*/ 1661 p->defaults.errh = srv->errh = fdlog; 1662 log_set_global_errh(srv->errh, 0); 1663 } 1664 cpv->v.v = errh = fdlog; 1665 cpv->vtype = T_CONFIG_LOCAL; 1666 1667 if (0 == i && errh != srv->errh) /*(top-level server.breakagelog)*/ 1668 serrh = errh; 1669 } 1670 } 1671 1672 if (config_feature_bool(srv, "server.errorlog-high-precision", 0)) 1673 log_set_global_errh(srv->errh, 1); 1674 1675 if (srv->srvconf.errorlog_use_syslog) /*(restricted to global scope)*/ 1676 config_log_error_open_syslog(srv, srv->errh, 1677 srv->srvconf.syslog_facility); 1678 else if (srv->errh->mode == FDLOG_FD && !srv->srvconf.dont_daemonize) 1679 srv->errh->fd = -1; 1680 /* We can only log to stderr in dont-daemonize mode; 1681 * if we do daemonize and no errorlog file is specified, 1682 * we log into /dev/null 1683 */ 1684 1685 /* Note: serrh should not be stored in p->defaults.serrh 1686 * If left as NULL, scripts (e.g. mod_cgi and mod_ssi exec) will inherit 1687 * the current STDERR_FILENO, which already is the top-level breakagelog. */ 1688 /*p->defaults.serrh = serrh;*/ 1689 1690 int errfd; 1691 if (NULL != serrh) { 1692 if (srv->errh->mode == FDLOG_FD) { 1693 srv->errh->fd = dup(STDERR_FILENO); 1694 fdevent_setfd_cloexec(srv->errh->fd); 1695 } 1696 1697 errfd = serrh->fd; 1698 if (*serrh->fn == '|') fdlog_pipe_serrh(errfd); /* breakagelog */ 1699 } 1700 else if (!srv->srvconf.dont_daemonize) { 1701 /* move STDERR_FILENO to /dev/null */ 1702 if (-1 == (errfd = fdevent_open_devnull())) { 1703 log_perror(srv->errh,__FILE__,__LINE__,"opening /dev/null failed"); 1704 return -1; 1705 } 1706 } 1707 else { 1708 /*(leave STDERR_FILENO as-is)*/ 1709 errfd = -1; 1710 } 1711 1712 if (0 != fdevent_set_stdin_stdout_stderr(-1, -1, errfd)) { 1713 log_perror(srv->errh, __FILE__, __LINE__, "setting stderr failed"); 1714 #ifdef FD_CLOEXEC 1715 if (-1 != errfd && NULL == serrh) close(errfd); 1716 #endif 1717 return -1; 1718 } 1719 #ifdef FD_CLOEXEC 1720 if (-1 != errfd && NULL == serrh) close(errfd); 1721 #endif 1722 1723 if (NULL != serrh) { 1724 close(errfd); /* serrh->fd */ 1725 serrh->fd = STDERR_FILENO; 1726 } 1727 1728 return 0; 1729 } 1730 1731 void config_log_error_close(server *srv) { 1732 config_data_base * const p = srv->config_data_base; 1733 if (NULL == p) return; 1734 1735 /*(reset serrh just in case; should not be used after this func returns)*/ 1736 p->defaults.serrh = NULL; 1737 1738 fdlog_closeall(srv->errh); /*(close all except srv->errh)*/ 1739 1740 if (srv->errh->mode == FDLOG_SYSLOG) { 1741 srv->errh->mode = FDLOG_FD; 1742 srv->errh->fd = STDERR_FILENO; 1743 #ifdef HAVE_SYSLOG_H 1744 closelog(); 1745 #endif 1746 } 1747 } 1748 1749 1750 1751 typedef struct { 1752 const char *source; 1753 const char *input; 1754 int offset; 1755 int size; 1756 1757 int line_pos; 1758 int line; 1759 1760 int in_key; 1761 int parens; 1762 int in_cond; 1763 int simulate_eol; 1764 log_error_st *errh; 1765 } tokenizer_t; 1766 1767 __attribute_pure__ 1768 static int config_skip_newline(const tokenizer_t * const t) { 1769 const char * const s = t->input + t->offset; 1770 /*force_assert(s[0] == '\r' || s[0] == '\n');*/ 1771 return 1 + (s[0] == '\r' && s[1] == '\n'); 1772 } 1773 1774 __attribute_noinline__ 1775 __attribute_pure__ 1776 static int config_skip_comment(const tokenizer_t * const t) { 1777 /*assert(t->input[t->offset] == '#');*/ 1778 const char *s = t->input + t->offset; 1779 do { ++s; } while (*s && *s != '\r' && *s != '\n'); 1780 return (int)(s - t->input); 1781 } 1782 1783 __attribute_cold__ 1784 static int config_tokenizer_err(tokenizer_t *t, const char *file, unsigned int line, const char *msg) { 1785 log_error(t->errh, file, line, "source: %s line: %d pos: %d %s", 1786 t->source, t->line, t->offset - t->line_pos, msg); 1787 return -1; 1788 } 1789 1790 static int config_tokenizer(tokenizer_t *t, buffer *token) { 1791 if (t->simulate_eol) { 1792 t->simulate_eol = 0; 1793 t->in_key = 1; 1794 buffer_copy_string_len(token, CONST_STR_LEN("(EOL)")); 1795 return TK_EOL; 1796 } 1797 1798 while (t->offset < t->size) { 1799 const char * const s = t->input + t->offset; 1800 switch (s[0]) { 1801 case '\t': 1802 case ' ': 1803 t->offset++; 1804 break; 1805 case '=': 1806 if (t->parens) { 1807 if (s[1] != '>') 1808 return config_tokenizer_err(t, __FILE__, __LINE__, 1809 "use => for assignments in arrays"); 1810 t->offset += 2; 1811 buffer_copy_string_len(token, s, 2); /* "=>" */ 1812 return TK_ARRAY_ASSIGN; 1813 } 1814 else if (t->in_cond) { 1815 int tid; 1816 switch (s[1]) { 1817 case '=': tid = TK_EQ; break; 1818 case '~': tid = TK_MATCH; break; 1819 case '^': tid = TK_PREFIX; break; 1820 case '$': tid = TK_SUFFIX; break; 1821 default: 1822 return config_tokenizer_err(t, __FILE__, __LINE__, 1823 "only == =~ =^ =$ are allowed in the condition"); 1824 } 1825 t->offset += 2; 1826 t->in_key = 1; 1827 t->in_cond = 0; 1828 buffer_copy_string_len(token, s, 2); /* "==" "=~" "=^" "=$" */ 1829 return tid; 1830 } 1831 else if (t->in_key) { 1832 t->offset++; 1833 buffer_copy_string_len(token, s, 1); /* "=" */ 1834 return TK_ASSIGN; 1835 } 1836 else 1837 return config_tokenizer_err(t, __FILE__, __LINE__, 1838 "unexpected equal-sign: ="); 1839 case '!': 1840 if (t->in_cond) { 1841 int tid; 1842 switch (s[1]) { 1843 case '=': tid = TK_NE; break; 1844 case '~': tid = TK_NOMATCH; break; 1845 default: 1846 return config_tokenizer_err(t, __FILE__, __LINE__, 1847 "only !~ and != are allowed in the condition"); 1848 } 1849 t->offset += 2; 1850 t->in_key = 1; 1851 t->in_cond = 0; 1852 buffer_copy_string_len(token, s, 2); /* "!=" "!~" */ 1853 return tid; 1854 } 1855 else 1856 return config_tokenizer_err(t, __FILE__, __LINE__, 1857 "unexpected exclamation-marks: !"); 1858 case '\n': 1859 case '\r': 1860 do { 1861 switch (t->input[t->offset]) { 1862 case '\r': 1863 case '\n': 1864 t->offset += config_skip_newline(t); 1865 t->line_pos = t->offset; 1866 t->line++; 1867 continue; 1868 case '#': 1869 t->offset = config_skip_comment(t); 1870 continue; 1871 case '\t': 1872 case ' ': 1873 t->offset++; 1874 continue; 1875 default: 1876 break; 1877 } 1878 break; 1879 } while (t->offset < t->size); 1880 if (!t->parens) { 1881 t->in_key = 1; 1882 buffer_copy_string_len(token, CONST_STR_LEN("(EOL)")); 1883 return TK_EOL; 1884 } 1885 break; 1886 case ',': 1887 t->offset++; 1888 if (t->parens) { 1889 buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)")); 1890 return TK_COMMA; 1891 } 1892 break; 1893 case '"': 1894 { 1895 /* search for the terminating " */ 1896 const char *start = s + 1; /*buffer_blank(token);*/ 1897 buffer_copy_string_len(token, CONST_STR_LEN("")); 1898 1899 int i; 1900 for (i = 1; s[i] && s[i] != '"'; ++i) { 1901 if (s[i] == '\\' && s[i+1] == '"') { 1902 buffer_append_string_len(token, start, s + i - start); 1903 start = s + ++i; /* step over '"' */ 1904 } 1905 } 1906 1907 if (s[i] == '\0') { 1908 return config_tokenizer_err(t, __FILE__, __LINE__, 1909 "missing closing quote"); 1910 } 1911 1912 t->offset += i + 1; 1913 buffer_append_string_len(token, start, s + i - start); 1914 return TK_STRING; 1915 } 1916 case '(': 1917 t->offset++; 1918 t->parens++; 1919 buffer_copy_string_len(token, s, 1); /* "(" */ 1920 return TK_LPARAN; 1921 case ')': 1922 if (!t->parens) 1923 return config_tokenizer_err(t, __FILE__, __LINE__, 1924 "close-parens seen open-parens"); 1925 t->offset++; 1926 t->parens--; 1927 buffer_copy_string_len(token, s, 1); /* ")" */ 1928 return TK_RPARAN; 1929 case '$': 1930 t->offset++; 1931 t->in_cond = 1; 1932 t->in_key = 0; 1933 buffer_copy_string_len(token, s, 1); /* "$" */ 1934 return TK_DOLLAR; 1935 case '+': 1936 if (s[1] == '=') { 1937 t->offset += 2; 1938 buffer_copy_string_len(token, s, 2); /* "+=" */ 1939 return TK_APPEND; 1940 } 1941 else { 1942 t->offset++; 1943 buffer_copy_string_len(token, s, 1); /* "+" */ 1944 return TK_PLUS; 1945 } 1946 case ':': 1947 if (s[1] != '=') 1948 return config_tokenizer_err(t, __FILE__, __LINE__, 1949 "unexpected character ':'"); 1950 t->offset += 2; 1951 buffer_copy_string_len(token, s, 2); /* ":=" */ 1952 return TK_FORCE_ASSIGN; 1953 case '{': 1954 t->offset++; 1955 buffer_copy_string_len(token, s, 1); /* "{" */ 1956 return TK_LCURLY; 1957 case '}': 1958 while (++t->offset < t->size) { 1959 int c = t->input[t->offset]; 1960 if (c == '\r' || c == '\n') { 1961 break; 1962 } 1963 else if (c == '#') { 1964 t->offset = config_skip_comment(t); 1965 break; 1966 } 1967 else if (c != ' ' && c != '\t') { 1968 t->simulate_eol = 1; 1969 break; 1970 } /* else (c == ' ' || c == '\t') */ 1971 } 1972 buffer_copy_string_len(token, s, 1); /* "}" */ 1973 return TK_RCURLY; 1974 case '[': 1975 t->offset++; 1976 buffer_copy_string_len(token, s, 1); /* "[" */ 1977 return TK_LBRACKET; 1978 case ']': 1979 t->offset++; 1980 buffer_copy_string_len(token, s, 1); /* "]" */ 1981 return TK_RBRACKET; 1982 case '#': 1983 t->offset = config_skip_comment(t); 1984 break; 1985 case '\0': 1986 config_tokenizer_err(t, __FILE__, __LINE__, "stray NUL"); 1987 return 0; 1988 default: 1989 if (t->in_cond) { 1990 int i = 0; 1991 while (light_isalpha(s[i]) || s[i] == '_') ++i; 1992 if (i && s[i]) { 1993 t->offset += i; 1994 buffer_copy_string_len(token, s, i); 1995 return TK_SRVVARNAME; 1996 } 1997 else 1998 return config_tokenizer_err(t, __FILE__, __LINE__, 1999 "invalid character in condition"); 2000 } 2001 else if (light_isdigit(s[0])) { 2002 /* take all digits */ 2003 int i = 1; 2004 while (light_isdigit(s[i])) ++i; 2005 t->offset += i; 2006 buffer_copy_string_len(token, s, i); 2007 return TK_INTEGER; 2008 } 2009 else { 2010 /* the key might consist of [-.0-9a-z] */ 2011 int i = 0; 2012 while (light_isalnum(s[i]) 2013 || s[i] == '.' 2014 || s[i] == '_' /* for env.* */ 2015 || s[i] == '-') ++i; 2016 2017 if (i && s[i]) { 2018 t->offset += i; 2019 buffer_copy_string_len(token, s, i); 2020 if (0 == strcmp(token->ptr, "include")) 2021 return TK_INCLUDE; 2022 else if (0 == strcmp(token->ptr, "include_shell")) 2023 return TK_INCLUDE_SHELL; 2024 else if (0 == strcmp(token->ptr, "global")) 2025 return TK_GLOBAL; 2026 else if (0 == strcmp(token->ptr, "else")) 2027 return TK_ELSE; 2028 else 2029 return TK_LKEY; 2030 } 2031 else if (0 == i 2032 && ((uint8_t *)s)[0] == 0xc2 2033 && ((uint8_t *)s)[1] == 0xa0) { 2034 /* treat U+00A0 (c2 a0) "NO-BREAK SPACE" as whitespace */ 2035 /* http://www.fileformat.info/info/unicode/char/a0/index.htm */ 2036 t->offset+=2; 2037 } 2038 else 2039 return config_tokenizer_err(t, __FILE__, __LINE__, 2040 "invalid character in variable name"); 2041 } 2042 break; 2043 } 2044 } 2045 return 0; 2046 } 2047 2048 static int config_parse(server *srv, config_t *context, const char *source, const char *input, int isize) { 2049 tokenizer_t t; 2050 buffer * const lasttoken = buffer_init(); 2051 int ret; 2052 2053 t.source = source; 2054 t.input = input; 2055 t.size = isize; 2056 t.offset = 0; 2057 t.line = 1; 2058 t.line_pos = 0; 2059 2060 t.in_key = 1; 2061 t.parens = 0; 2062 t.in_cond = 0; 2063 t.simulate_eol = 0; 2064 t.errh = srv->errh; 2065 2066 void * const pParser = configparserAlloc( malloc ); 2067 force_assert(pParser); 2068 do { 2069 ret = config_tokenizer(&t, lasttoken); 2070 if (__builtin_expect( (ret <= 0), 0)) 2071 break; 2072 buffer * const token = buffer_init(); 2073 buffer_copy_buffer(token, lasttoken); 2074 configparser(pParser, ret, token, context); 2075 /*token = NULL;*/ 2076 } while (context->ok); 2077 2078 if (ret != -1 && context->ok) { 2079 /* add an EOL at EOF, better than say sorry */ 2080 buffer * const token = buffer_init(); 2081 buffer_copy_string(token, "(EOL)"); 2082 configparser(pParser, TK_EOL, token, context); 2083 /*token = NULL;*/ 2084 if (context->ok) { 2085 configparser(pParser, 0, NULL, context); 2086 } 2087 } 2088 configparserFree(pParser, free); 2089 2090 if (ret == -1) { 2091 log_error(t.errh, __FILE__, __LINE__, 2092 "configfile parser failed at: %s", lasttoken->ptr); 2093 } else if (context->ok == 0) { 2094 log_error(t.errh, __FILE__, __LINE__, "source: %s line: %d pos: %d " 2095 "parser failed somehow near here: %s", 2096 t.source, t.line, t.offset - t.line_pos, lasttoken->ptr); 2097 ret = -1; 2098 } 2099 buffer_free(lasttoken); 2100 2101 return ret == -1 ? -1 : 0; 2102 } 2103 2104 __attribute_cold__ 2105 static int config_parse_stdin(server *srv, config_t *context) { 2106 buffer * const b = chunk_buffer_acquire(); 2107 size_t dlen; 2108 ssize_t n = -1; 2109 do { 2110 if (n > 0) 2111 buffer_commit(b, n); 2112 size_t avail = buffer_string_space(b); 2113 dlen = buffer_clen(b); 2114 if (__builtin_expect( (avail < 1024), 0)) { 2115 /*(arbitrary limit: 32 MB file; expect < 1 MB)*/ 2116 if (dlen >= 32*1024*1024) { 2117 log_error(srv->errh, __FILE__, __LINE__, 2118 "config read from stdin is way too large"); 2119 break; 2120 } 2121 avail = chunk_buffer_prepare_append(b, b->size+avail); 2122 } 2123 n = read(STDIN_FILENO, b->ptr+dlen, avail); 2124 } while (n > 0 || (n == -1 && errno == EINTR)); 2125 int rc = -1; 2126 if (0 == n) 2127 rc = dlen ? config_parse(srv, context, "-", b->ptr, (int)dlen) : 0; 2128 else 2129 log_perror(srv->errh, __FILE__, __LINE__, "config read from stdin"); 2130 2131 if (dlen) 2132 ck_memzero(b->ptr, dlen); 2133 chunk_buffer_release(b); 2134 return rc; 2135 } 2136 2137 static int config_parse_file_stream(server *srv, config_t *context, const char *fn) { 2138 off_t dlen = 32*1024*1024;/*(arbitrary limit: 32 MB file; expect < 1 MB)*/ 2139 char *data = fdevent_load_file(fn, &dlen, NULL, malloc, free); 2140 if (NULL == data) { 2141 log_perror(srv->errh, __FILE__, __LINE__, 2142 "opening configfile %s failed", fn); 2143 return -1; 2144 } 2145 2146 int rc = 0; 2147 if (dlen) { 2148 rc = config_parse(srv, context, fn, data, (int)dlen); 2149 ck_memzero(data, (size_t)dlen); 2150 } 2151 free(data); 2152 return rc; 2153 } 2154 2155 int config_parse_file(server *srv, config_t *context, const char *fn) { 2156 buffer * const filename = buffer_init(); 2157 const size_t fnlen = strlen(fn); 2158 int ret = -1; 2159 #ifdef GLOB_BRACE 2160 int flags = GLOB_BRACE; 2161 #else 2162 int flags = 0; 2163 #endif 2164 glob_t gl; 2165 2166 if ((fn[0] == '/' || fn[0] == '\\') || 2167 (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\')) || 2168 (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\'))) { 2169 buffer_copy_string_len(filename, fn, fnlen); 2170 } else { 2171 buffer_copy_path_len2(filename, BUF_PTR_LEN(context->basedir), 2172 fn, fnlen); 2173 } 2174 2175 switch (glob(filename->ptr, flags, NULL, &gl)) { 2176 case 0: 2177 for (size_t i = 0; i < gl.gl_pathc; ++i) { 2178 ret = config_parse_file_stream(srv, context, gl.gl_pathv[i]); 2179 if (0 != ret) break; 2180 } 2181 globfree(&gl); 2182 break; 2183 case GLOB_NOMATCH: 2184 if (filename->ptr[strcspn(filename->ptr, "*?[]{}")] != '\0') { /*(contains glob metachars)*/ 2185 ret = 0; /* not an error if no files match glob pattern */ 2186 } 2187 else { 2188 log_error(srv->errh, __FILE__, __LINE__, "include file not found: %s", filename->ptr); 2189 } 2190 break; 2191 case GLOB_ABORTED: 2192 case GLOB_NOSPACE: 2193 log_perror(srv->errh, __FILE__, __LINE__, "glob() %s failed", filename->ptr); 2194 break; 2195 } 2196 2197 buffer_free(filename); 2198 return ret; 2199 } 2200 2201 #ifdef __CYGWIN__ 2202 2203 static char* getCWD(char *buf, size_t sz) { 2204 if (NULL == getcwd(buf, sz)) { 2205 return NULL; 2206 } 2207 for (size_t i = 0; buf[i]; ++i) { 2208 if (buf[i] == '\\') buf[i] = '/'; 2209 } 2210 return buf; 2211 } 2212 2213 #define getcwd(buf, sz) getCWD((buf),(sz)) 2214 2215 #endif /* __CYGWIN__ */ 2216 2217 int config_parse_cmd(server *srv, config_t *context, const char *cmd) { 2218 int ret = 0; 2219 int fds[2]; 2220 char oldpwd[PATH_MAX]; 2221 2222 if (NULL == getcwd(oldpwd, sizeof(oldpwd))) { 2223 log_perror(srv->errh, __FILE__, __LINE__, "getcwd()"); 2224 return -1; 2225 } 2226 2227 if (!buffer_is_blank(context->basedir)) { 2228 if (0 != chdir(context->basedir->ptr)) { 2229 log_perror(srv->errh, __FILE__, __LINE__, 2230 "cannot change directory to %s", context->basedir->ptr); 2231 return -1; 2232 } 2233 } 2234 2235 if (fdevent_pipe_cloexec(fds, 65536)) { 2236 log_perror(srv->errh, __FILE__, __LINE__, "pipe()"); 2237 ret = -1; 2238 } 2239 else { 2240 char *shell = getenv("SHELL"); 2241 char *args[4]; 2242 pid_t pid; 2243 if (shell && (0 == strcmp(shell, "/usr/bin/false") 2244 || 0 == strcmp(shell, "/bin/false"))) 2245 shell = NULL; 2246 *(const char **)&args[0] = shell ? shell : "/bin/sh"; 2247 *(const char **)&args[1] = "-c"; 2248 *(const char **)&args[2] = cmd; 2249 args[3] = NULL; 2250 2251 pid = fdevent_fork_execve(args[0], args, NULL, -1, fds[1], -1, -1); 2252 if (-1 == pid) { 2253 log_perror(srv->errh, __FILE__, __LINE__, "fork/exec(%s)", cmd); 2254 ret = -1; 2255 } 2256 else { 2257 ssize_t rd; 2258 int wstatus = 0; 2259 buffer *out = buffer_init(); 2260 close(fds[1]); 2261 fds[1] = -1; 2262 do { 2263 rd = read(fds[0], buffer_string_prepare_append(out, 1023), 1023); 2264 if (rd >= 0) buffer_commit(out, (size_t)rd); 2265 } while (rd > 0 || (-1 == rd && errno == EINTR)); 2266 if (0 != rd) { 2267 log_perror(srv->errh, __FILE__, __LINE__, "read \"%s\"", cmd); 2268 ret = -1; 2269 } 2270 close(fds[0]); 2271 fds[0] = -1; 2272 if (pid != fdevent_waitpid(pid, &wstatus, 0)) { 2273 log_perror(srv->errh, __FILE__, __LINE__, "waitpid \"%s\"",cmd); 2274 ret = -1; 2275 } 2276 if (0 != wstatus) { 2277 log_error(srv->errh, __FILE__, __LINE__, 2278 "command \"%s\" exited non-zero: %d", 2279 cmd, WEXITSTATUS(wstatus)); 2280 ret = -1; 2281 } 2282 2283 if (-1 != ret) { 2284 ret = config_parse(srv, context, cmd, BUF_PTR_LEN(out)); 2285 } 2286 buffer_free(out); 2287 } 2288 if (-1 != fds[0]) close(fds[0]); 2289 if (-1 != fds[1]) close(fds[1]); 2290 } 2291 2292 if (0 != chdir(oldpwd)) { 2293 log_perror(srv->errh, __FILE__, __LINE__, 2294 "cannot change directory to %s", oldpwd); 2295 ret = -1; 2296 } 2297 return ret; 2298 } 2299 2300 static int config_remoteip_normalize_ipv6(buffer * const b, buffer * const tb) { 2301 /* $HTTP["remote-ip"] IPv6 accepted with or without '[]' for config compat 2302 * http_request_host_normalize() expects IPv6 with '[]', 2303 * and config processing at runtime expects COMP_HTTP_REMOTE_IP 2304 * compared without '[]', so strip '[]' after normalization */ 2305 buffer_clear(tb); 2306 if (b->ptr[0] != '[') 2307 buffer_append_str3(tb, 2308 CONST_STR_LEN("["), 2309 BUF_PTR_LEN(b), 2310 CONST_STR_LEN("]")); 2311 else 2312 buffer_append_string_buffer(tb, b); 2313 2314 int rc = http_request_host_normalize(tb, 0); 2315 if (0 == rc) { 2316 /* remove surrounding '[]' */ 2317 size_t blen = buffer_clen(tb); 2318 if (blen > 1) buffer_copy_string_len(b, tb->ptr+1, blen-2); 2319 } 2320 return rc; 2321 } 2322 2323 int config_remoteip_normalize(buffer * const b, buffer * const tb) { 2324 if (b->ptr[0] == '/') return 1; /*(skip AF_UNIX /path/file)*/ 2325 2326 const char * const slash = strchr(b->ptr, '/'); /* CIDR mask */ 2327 const char * const colon = strchr(b->ptr, ':'); /* IPv6 */ 2328 unsigned long nm_bits = 0; 2329 2330 if (NULL != slash) { 2331 char *nptr; 2332 nm_bits = strtoul(slash + 1, &nptr, 10); 2333 if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) { 2334 /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/ 2335 return -1; 2336 } 2337 buffer_truncate(b, (size_t)(slash - b->ptr)); 2338 } 2339 2340 int family = colon ? AF_INET6 : AF_INET; 2341 int rc = (family == AF_INET) 2342 ? http_request_host_normalize(b, 0) 2343 : config_remoteip_normalize_ipv6(b, tb); 2344 2345 uint32_t len = buffer_clen(b); /*(save len before adding CIDR mask)*/ 2346 if (nm_bits) { 2347 buffer_append_char(b, '/'); 2348 buffer_append_int(b, (int)nm_bits); 2349 } 2350 2351 if (0 != rc) { 2352 return -1; 2353 } 2354 2355 /* extend b to hold structured data after end of string: 2356 * nm_bits and memory-aligned sock_addr for AF_INET or AF_INET6 (28 bytes)*/ 2357 char *after = buffer_string_prepare_append(b, 1 + 7 + 28); 2358 ++after; /*(increment to pos after string end '\0')*/ 2359 *(unsigned char *)after = (unsigned char)nm_bits; 2360 sock_addr * const addr = (sock_addr *)(((uintptr_t)after+1+7) & ~7); 2361 if (nm_bits) b->ptr[len] = '\0'; /*(sock_addr_inet_pton() w/o CIDR mask)*/ 2362 rc = sock_addr_inet_pton(addr, b->ptr, family, 0); 2363 if (nm_bits) b->ptr[len] = '/'; 2364 return (1 == rc); 2365 } 2366 2367 2368 static void context_init(server *srv, config_t *context) { 2369 context->srv = srv; 2370 context->ok = 1; 2371 vector_config_weak_init(&context->configs_stack); 2372 context->basedir = buffer_init(); 2373 } 2374 2375 static void context_free(config_t *context) { 2376 vector_config_weak_clear(&context->configs_stack); 2377 buffer_free(context->basedir); 2378 } 2379 2380 __attribute_noinline__ 2381 static void config_vars_init (array *a) { 2382 char dcwd[PATH_MAX]; 2383 if (NULL != getcwd(dcwd, sizeof(dcwd))) 2384 array_set_key_value(a, CONST_STR_LEN("var.CWD"), dcwd, strlen(dcwd)); 2385 2386 *array_get_int_ptr(a, CONST_STR_LEN("var.PID")) = getpid(); 2387 } 2388 2389 int config_read(server *srv, const char *fn) { 2390 config_t context; 2391 data_config *dc; 2392 int ret; 2393 char *pos; 2394 2395 context_init(srv, &context); 2396 context.all_configs = srv->config_context; 2397 2398 #ifdef __WIN32 2399 pos = strrchr(fn, '\\'); 2400 #else 2401 pos = strrchr(fn, '/'); 2402 #endif 2403 if (pos) { 2404 buffer_copy_string_len(context.basedir, fn, pos - fn + 1); 2405 } 2406 2407 dc = data_config_init(); 2408 buffer_copy_string_len(&dc->key, CONST_STR_LEN("global")); 2409 config_vars_init(dc->value); /* default context */ 2410 2411 force_assert(context.all_configs->used == 0); 2412 dc->context_ndx = context.all_configs->used; 2413 array_insert_unique(context.all_configs, (data_unset *)dc); 2414 context.current = dc; 2415 2416 ret = (0 != strcmp(fn, "-")) /*(incompatible with one-shot mode)*/ 2417 ? config_parse_file_stream(srv, &context, fn) 2418 : config_parse_stdin(srv, &context); 2419 2420 /* remains nothing if parser is ok */ 2421 force_assert(!(0 == ret && context.ok && 0 != context.configs_stack.used)); 2422 context_free(&context); 2423 2424 if (0 != ret) { 2425 return ret; 2426 } 2427 2428 /* reorder dc->context_ndx to match srv->config_context->data[] index. 2429 * srv->config_context->data[] may have been re-ordered in configparser.y. 2430 * Since the dc->context_ndx (id) is reused by config_insert*() and by 2431 * plugins to index into srv->config_context->data[], reorder into the 2432 * order encountered during config file parsing for least surprise to 2433 * end-users writing config files. Note: this manipulation *breaks* the 2434 * srv->config_context->sorted[] structure, so searching the array by key 2435 * is no longer valid. */ 2436 for (uint32_t i = 0; i < srv->config_context->used; ++i) { 2437 dc = (data_config *)srv->config_context->data[i]; 2438 if (dc->context_ndx == (int)i) continue; 2439 for (uint32_t j = i; j < srv->config_context->used; ++j) { 2440 dc = (data_config *)srv->config_context->data[j]; 2441 if (dc->context_ndx == (int)i) { 2442 srv->config_context->data[j] = srv->config_context->data[i]; 2443 srv->config_context->data[i] = (data_unset *)dc; 2444 break; 2445 } 2446 } 2447 } 2448 2449 if (0 != config_insert_srvconf(srv)) { 2450 return -1; 2451 } 2452 2453 if (0 != config_insert(srv)) { 2454 return -1; 2455 } 2456 2457 return 0; 2458 } 2459 2460 int config_set_defaults(server *srv) { 2461 size_t i; 2462 request_config *s = &((config_data_base *)srv->config_data_base)->defaults; 2463 struct stat st1, st2; 2464 2465 if (fdevent_config(&srv->srvconf.event_handler, srv->errh) <= 0) 2466 return -1; 2467 2468 if (srv->srvconf.changeroot) { 2469 if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) { 2470 log_error(srv->errh, __FILE__, __LINE__, 2471 "server.chroot doesn't exist: %s", 2472 srv->srvconf.changeroot->ptr); 2473 return -1; 2474 } 2475 if (!S_ISDIR(st1.st_mode)) { 2476 log_error(srv->errh, __FILE__, __LINE__, 2477 "server.chroot isn't a directory: %s", 2478 srv->srvconf.changeroot->ptr); 2479 return -1; 2480 } 2481 } 2482 2483 if (!srv->srvconf.upload_tempdirs->used) { 2484 const char *tmpdir = getenv("TMPDIR"); 2485 if (NULL == tmpdir) tmpdir = "/var/tmp"; 2486 array_insert_value(srv->srvconf.upload_tempdirs, tmpdir, strlen(tmpdir)); 2487 } 2488 2489 if (srv->srvconf.upload_tempdirs->used) { 2490 buffer * const tb = srv->tmp_buf; 2491 buffer_clear(tb); 2492 if (srv->srvconf.changeroot) { 2493 buffer_copy_buffer(tb, srv->srvconf.changeroot); 2494 } 2495 const size_t len = buffer_clen(tb); 2496 2497 for (i = 0; i < srv->srvconf.upload_tempdirs->used; ++i) { 2498 const data_string * const ds = (data_string *)srv->srvconf.upload_tempdirs->data[i]; 2499 if (len) { 2500 buffer_truncate(tb, len); 2501 buffer_append_path_len(tb, BUF_PTR_LEN(&ds->value)); 2502 } else { 2503 buffer_copy_buffer(tb, &ds->value); 2504 } 2505 if (-1 == stat(tb->ptr, &st1)) { 2506 log_error(srv->errh, __FILE__, __LINE__, 2507 "server.upload-dirs doesn't exist: %s", tb->ptr); 2508 } else if (!S_ISDIR(st1.st_mode)) { 2509 log_error(srv->errh, __FILE__, __LINE__, 2510 "server.upload-dirs isn't a directory: %s", tb->ptr); 2511 } 2512 } 2513 } 2514 2515 chunkqueue_set_tempdirs_default( 2516 srv->srvconf.upload_tempdirs, 2517 srv->srvconf.upload_temp_file_size); 2518 2519 if (!s->document_root || buffer_is_blank(s->document_root)) { 2520 log_error(srv->errh, __FILE__, __LINE__, "server.document-root is not set"); 2521 return -1; 2522 } 2523 2524 if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */ 2525 s->force_lowercase_filenames = 0; /* default to 0 */ 2526 2527 buffer * const tb = srv->tmp_buf; 2528 buffer_copy_string_len_lc(tb, BUF_PTR_LEN(s->document_root)); 2529 2530 if (0 == stat(tb->ptr, &st1)) { 2531 int is_lower = 0; 2532 2533 is_lower = buffer_is_equal(tb, s->document_root); 2534 2535 /* lower-case existed, check upper-case */ 2536 buffer_copy_buffer(tb, s->document_root); 2537 2538 buffer_to_upper(tb); 2539 2540 /* we have to handle the special case that upper and lower-casing results in the same filename 2541 * as in server.document-root = "/" or "/12345/" */ 2542 2543 if (is_lower && buffer_is_equal(tb, s->document_root)) { 2544 /* lower-casing and upper-casing didn't result in 2545 * an other filename, no need to stat(), 2546 * just assume it is case-sensitive. */ 2547 2548 s->force_lowercase_filenames = 0; 2549 } else if (0 == stat(tb->ptr, &st2)) { 2550 2551 /* upper case exists too, doesn't the FS handle this ? */ 2552 2553 /* upper and lower have the same inode -> case-insensitve FS */ 2554 2555 if (st1.st_ino == st2.st_ino) { 2556 /* upper and lower have the same inode -> case-insensitve FS */ 2557 2558 s->force_lowercase_filenames = 1; 2559 } 2560 } 2561 } 2562 } 2563 2564 return 0; 2565 } 2566