UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "../public/nsapi.h" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 34 #include <fcntl.h> 35 #include <sys/types.h> 36 #include <sys/file.h> 37 #include <sys/stat.h> 38 #include <sys/mman.h> 39 40 #include <ucx/string.h> 41 #include <ucx/utils.h> 42 43 #include "httplistener.h" 44 #include "config.h" 45 #include "func.h" 46 #include "log.h" 47 #include "event.h" 48 #include "threadpools.h" 49 #include "ldap_auth.h" 50 #include "configmanager.h" 51 52 #include "vserver.h" 53 #include "../util/pblock.h" 54 #include "../util/util.h" 55 #include "../util/atomic.h" 56 #include "ucx/buffer.h" 57 58 pool_handle_t *cfg_pool; 59 60 // TODO: Funktion für ConfigDirective -> directive 61 // TODO: Funktion für UcxList parameter list -> pblock 62 63 int load_init_conf(char *file) { 64 log_ereport(LOG_VERBOSE, "load_init_conf"); 65 66 InitConfig *cfg = load_init_config(file); 67 if(cfg == NULL) { 68 log_ereport(LOG_FAILURE, "Cannot load init.conf"); 69 return 1; 70 } 71 UcxAllocator *mp = cfg->parser.mp; 72 73 cfg_pool = pool_create(); // one pool for one Configuration 74 UcxList *dirs = cfg->directives; 75 while(dirs != NULL) { 76 ConfigDirective *dir = dirs->data; 77 78 /* create NSAPI directive */ 79 directive *d = malloc(sizeof(directive)); 80 d->param = pblock_create_pool(cfg_pool, 8); 81 UcxList *param = cfg_param_list(dir->value, mp); 82 while(param != NULL) { 83 ConfigParam *p = param->data; 84 pblock_nvlinsert( 85 p->name.ptr, 86 p->name.length, 87 p->value.ptr, 88 p->value.length, 89 d->param); 90 91 param = param->next; 92 } 93 94 /* get function */ 95 char *func_name = pblock_findval("fn", d->param); 96 d->func = get_function(func_name); 97 if(d->func == NULL) { 98 pblock_free(d->param); 99 free(d); 100 //dirs = dirs->next; 101 log_ereport( 102 LOG_MISCONFIG, 103 "Cannot find Init function %s", 104 func_name); 105 return 1; 106 } 107 108 /* execute init directive */ 109 int ret = d->func->func(d->param, NULL, NULL); 110 if(ret != REQ_PROCEED && ret != REQ_NOACTION) { 111 log_ereport( 112 LOG_FAILURE, 113 "Error running Init function %s", 114 func_name); 115 pblock_free(d->param); 116 free(d); 117 return 1; 118 } 119 120 pblock_free(d->param); 121 free(d); 122 dirs = dirs->next; 123 } 124 125 free_init_config(cfg); 126 127 return 0; 128 } 129 130 ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file) { 131 log_ereport(LOG_VERBOSE, "load_server_conf"); 132 133 ServerConfig *serverconf = load_server_config(file); 134 if(serverconf == NULL) { 135 log_ereport(LOG_FAILURE, "Cannot load server.conf"); 136 } 137 ServerConfiguration *serverconfig = calloc(1, sizeof(ServerConfiguration)); 138 serverconfig->ref = 1; 139 serverconfig->pool = pool_create(); 140 serverconfig->listeners = NULL; 141 serverconfig->host_vs = ucx_map_new(16); 142 serverconfig->authdbs = ucx_map_new(16); 143 // TODO: init serverconfig stuff 144 145 146 /* 147 * convert ServerConfig to ServerConfiguration 148 * 149 * its important to do this in the correct order: 150 * LogFile (open log file first to log possible errors) 151 * Runtime 152 * Threadpool 153 * EventHandler 154 * AuthDB 155 * Listener (we set the VirtualServer later) 156 * VirtualServer (dependencies: Listener) 157 */ 158 159 /* 160 * free stuff on error 161 */ 162 163 // init logfile first 164 UcxList *lfl = ucx_map_sstr_get(serverconf->objects, sstrn("LogFile", 7)); 165 if(lfl != NULL) { 166 ServerConfigObject *logobj = lfl->data; 167 if(logobj == NULL) { 168 // error 169 return NULL; 170 } 171 172 int ret = cfg_handle_logfile(serverconfig, logobj); 173 if(ret != 0) { 174 // cannot initialize log file 175 return NULL; 176 } 177 } else { 178 // horrible error 179 return NULL; 180 } 181 182 UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); 183 UCX_FOREACH(elm, list) { 184 ServerConfigObject *scfgobj = elm->data; 185 if(cfg_handle_runtime(serverconfig, scfgobj)) { 186 // error 187 return NULL; 188 } 189 } 190 191 list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10)); 192 UCX_FOREACH(elm, list) { 193 if(cfg_handle_threadpool(serverconfig, elm->data)) { 194 return NULL; 195 } 196 } 197 // check thread pool config 198 if(check_thread_pool_cfg() != 0) { 199 /* critical error */ 200 return NULL; 201 } 202 203 list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12)); 204 UCX_FOREACH(elm, list) { 205 if(cfg_handle_eventhandler( 206 serverconfig, (ServerConfigObject*)elm->data)) { 207 // error 208 return NULL; 209 } 210 } 211 // check event handler config 212 if(check_event_handler_cfg() != 0) { 213 /* critical error */ 214 return NULL; 215 } 216 217 list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9)); 218 UCX_FOREACH(elm, list) { 219 ServerConfigObject *scfgobj = elm->data; 220 if(cfg_handle_accesslog(serverconfig, scfgobj)) { 221 return NULL; 222 } 223 } 224 225 list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6)); 226 UCX_FOREACH(elm, list) { 227 ServerConfigObject *scfgobj = elm->data; 228 if(cfg_handle_authdb(serverconfig, scfgobj)) { 229 return NULL; 230 } 231 } 232 233 list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8)); 234 UCX_FOREACH(elm, list) { 235 ServerConfigObject *scfgobj = elm->data; 236 if(cfg_handle_listener(serverconfig, scfgobj)) { 237 return NULL; 238 } 239 } 240 241 list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13)); 242 UCX_FOREACH(elm, list) { 243 ServerConfigObject *scfgobj = elm->data; 244 if(cfg_handle_vs(serverconfig, scfgobj)) { 245 return NULL; 246 } 247 } 248 249 250 // set VirtualServer for all listeners 251 UcxList *ls = serverconfig->listeners; 252 while(ls) { 253 HttpListener *listener = ls->data; 254 255 sstr_t vsname = sstr(listener->default_vs.vs_name); 256 257 // search for VirtualServer 258 //int b = 0; 259 UcxMapIterator iter = ucx_map_iterator(serverconfig->host_vs); 260 VirtualServer *vs; 261 UCX_MAP_FOREACH(key, vs, iter) { 262 if(!sstrcmp(vsname, vs->name)) { 263 listener->default_vs.vs = vs; 264 break; 265 } 266 } 267 268 ls = ls->next; 269 } 270 271 free_server_config(serverconf); 272 return serverconfig; 273 } 274 275 void cfg_ref(ServerConfiguration *cfg) { 276 ws_atomic_inc32(&cfg->ref); 277 } 278 279 void cfg_unref(ServerConfiguration *cfg) { 280 uint32_t ref = ws_atomic_dec32(&cfg->ref); 281 if(ref == 0) { 282 // TODO: free configuration 283 printf("free ServerConfiguration %""\n"PRIxPTR, (intptr_t)cfg); 284 } 285 } 286 287 288 void init_server_config_parser() { 289 290 } 291 292 int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) { 293 sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User")); 294 if(user.ptr) { 295 cfg->user = sstrdup_pool(cfg->pool, user); 296 } 297 sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp")); 298 if(tmp.ptr) { 299 cfg->tmp = sstrdup_pool(cfg->pool, tmp); 300 } else { 301 log_ereport(LOG_MISCONFIG, "no temporary directory specified"); 302 return -1; 303 } 304 305 // mime file 306 sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile")); 307 sstr_t base = sstr("config/"); 308 sstr_t file = sstrcat(2, base, mf); 309 310 ConfigFile *f = cfgmgr_get_file(file); 311 if(f == NULL) { 312 f = malloc(sizeof(ConfigFile)); 313 f->data = NULL; 314 f->file = sstrdup(file); 315 f->reload = mime_conf_reload; 316 f->last_modified = 0; 317 318 // load the file content 319 //f->reload(f, cfg); 320 if(cfgmgr_reload_file(f, cfg, NULL)) { 321 free(f->file.ptr); 322 free(f); 323 324 free(file.ptr); 325 return -1; 326 } 327 cfgmgr_attach_file(f); 328 } 329 330 cfg->mimetypes = f->data; 331 332 free(file.ptr); 333 return 0; 334 } 335 336 int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj) { 337 sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); 338 sstr_t lvl = cfg_directivelist_get_str(obj->directives, sstr("Level")); 339 340 if(file.ptr == NULL || lvl.ptr == NULL) { 341 /* missing log file parameters */ 342 return -1; 343 } 344 345 LogConfig logcfg; 346 logcfg.file = sstrdup(file).ptr; 347 logcfg.level = sstrdup(lvl).ptr; 348 logcfg.log_stdout = 0; 349 logcfg.log_stderr = 0; 350 /* TODO: stdout, stderr config */ 351 352 int ret = init_log_file(&logcfg); 353 354 free(logcfg.file); 355 free(logcfg.level); 356 357 return ret; 358 } 359 360 int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj) { 361 ThreadPoolConfig poolcfg; 362 poolcfg.min_threads = 4; 363 poolcfg.min_threads = 4; 364 poolcfg.max_threads = 8; 365 poolcfg.queue_size = 64; 366 poolcfg.stack_size = 262144; 367 368 sstr_t name = cfg_directivelist_get_str( 369 obj->directives, 370 sstr("Name")); 371 sstr_t min = cfg_directivelist_get_str( 372 obj->directives, 373 sstr("MinThreads")); 374 sstr_t max = cfg_directivelist_get_str( 375 obj->directives, 376 sstr("MaxThreads")); 377 sstr_t stack = cfg_directivelist_get_str( 378 obj->directives, 379 sstr("StackSize")); 380 sstr_t queue = cfg_directivelist_get_str( 381 obj->directives, 382 sstr("QueueSize")); 383 // TODO: Type 384 385 if(name.length == 0) { 386 // TODO: log error 387 return 1; 388 } 389 390 if(min.length != 0) { 391 min = sstrdup(min); 392 poolcfg.min_threads = atoi(min.ptr); 393 free(min.ptr); 394 } 395 396 if(max.length != 0) { 397 max = sstrdup(max); 398 poolcfg.max_threads = atoi(max.ptr); 399 free(max.ptr); 400 } 401 402 if(stack.length != 0) { 403 stack = sstrdup(stack); 404 poolcfg.stack_size = atoi(stack.ptr); 405 free(stack.ptr); 406 } 407 408 if(queue.length != 0) { 409 queue = sstrdup(queue); 410 poolcfg.queue_size = atoi(queue.ptr); 411 free(queue.ptr); 412 } 413 414 create_threadpool(name, &poolcfg); 415 416 return 0; 417 } 418 419 int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) { 420 EventHandlerConfig evcfg; 421 422 sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); 423 sstr_t threads = cfg_directivelist_get_str( 424 obj->directives, 425 sstr("Threads")); 426 sstr_t isdefault = cfg_directivelist_get_str( 427 obj->directives, 428 sstr("Default")); 429 430 evcfg.name = name; 431 432 sstr_t s = sstrdup(threads); 433 evcfg.nthreads = atoi(s.ptr); 434 free(s.ptr); 435 436 evcfg.isdefault = util_getboolean(isdefault.ptr, 0); 437 438 return create_event_handler(&evcfg); 439 } 440 441 int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) { 442 // TODO: use a name to identify the log file 443 444 sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); 445 if(file.ptr == NULL) { 446 return 0; 447 } 448 sstr_t format; 449 format.ptr = NULL; 450 format.length = 0; 451 452 //AccessLog *log = get_access_log(file, format); 453 LogFile *log_file = get_access_log_file(file); 454 if(!log_file) { 455 // TODO: error/warning 456 return 0; 457 } 458 AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog)); 459 log->file = sstrdup_pool(cfg->pool, file); 460 log->format = format; 461 log->log = log_file; 462 cfg->logfiles = ucx_list_append(cfg->logfiles, log); 463 464 if(!cfg->default_log) { 465 cfg->default_log = log; 466 } 467 468 return 0; 469 } 470 471 int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) { 472 sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); 473 sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type")); 474 475 if(!sstrcmp(type, sstr("ldap"))) { 476 LDAPConfig conf; 477 478 sstr_t host = cfg_directivelist_get_str( 479 obj->directives, 480 sstr("Host")); 481 sstr_t port = cfg_directivelist_get_str( 482 obj->directives, 483 sstr("Port")); 484 sstr_t basedn = cfg_directivelist_get_str( 485 obj->directives, 486 sstr("BaseDN")); 487 sstr_t binddn = cfg_directivelist_get_str( 488 obj->directives, 489 sstr("BindDN")); 490 sstr_t basepw = cfg_directivelist_get_str( 491 obj->directives, 492 sstr("BindPW")); 493 494 host = sstrdup(host); 495 port = sstrdup(port); 496 basedn = sstrdup(basedn); 497 binddn = sstrdup(binddn); 498 basepw = sstrdup(basepw); 499 500 conf.hostname = host.ptr; 501 conf.port = atoi(port.ptr); 502 conf.basedn = basedn.ptr; 503 conf.binddn = binddn.ptr; 504 conf.bindpw = basepw.ptr; 505 506 name = sstrdup(name); 507 508 AuthDB *authdb = create_ldap_authdb(name.ptr, &conf); 509 ucx_map_sstr_put(cfg->authdbs, name, authdb); 510 511 // TODO: create_ldap_authdb should copy the strings 512 /* 513 free(host.ptr); 514 free(port.ptr); 515 free(basedn.ptr); 516 free(binddn.ptr); 517 free(basepw.ptr); 518 free(name.ptr); 519 */ 520 521 } else if(!sstrcmp(type, sstr("keyfile"))) { 522 // we only need the file parameter 523 sstr_t file = cfg_directivelist_get_str( 524 obj->directives, 525 sstr("File")); 526 if(file.length == 0) { 527 log_ereport( 528 LOG_MISCONFIG, 529 "missing File parameter for keyfile authdb"); 530 return 1; 531 } 532 533 // load keyfile 534 ConfigFile *f = cfgmgr_get_file(file); 535 if(f == NULL) { 536 f = malloc(sizeof(ConfigFile)); 537 f->data = NULL; 538 f->file = sstrdup(file); 539 f->reload = keyfile_reload; 540 f->last_modified = 0; 541 //f->reload(f, cfg); 542 if(cfgmgr_reload_file(f, cfg, NULL)) { 543 free(f->file.ptr); 544 free(f); 545 return -1; 546 } 547 cfgmgr_attach_file(f); 548 } 549 550 // add keyfile authdb 551 Keyfile *keyfile = f->data; 552 keyfile->authdb.name = sstrdup(name).ptr; 553 ucx_map_sstr_put(cfg->authdbs, name, keyfile); 554 } 555 556 return 0; 557 } 558 559 int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) { 560 ListenerConfig lc; 561 ZERO(&lc, sizeof(ListenerConfig)); 562 lc.cfg = cfg; 563 lc.port = 8080; 564 lc.nacceptors = 1; 565 566 // TODO: use sstrdup_pool? 567 lc.name = sstrdup(cfg_directivelist_get_str( 568 obj->directives, 569 sstr("Name"))); 570 lc.port = atoi(cfg_directivelist_get_str( 571 obj->directives, 572 sstr("Port")).ptr); 573 lc.vs = sstrdup(cfg_directivelist_get_str( 574 obj->directives, 575 sstr("DefaultVS"))); 576 lc.threadpool = sstrdup(cfg_directivelist_get_str( 577 obj->directives, 578 sstr("Threadpool"))); 579 580 sstr_t blockingio = cfg_directivelist_get_str( 581 obj->directives, 582 sstr("BlockingIO")); 583 if(blockingio.ptr) { 584 lc.blockingio = util_getboolean_s(blockingio, WS_FALSE); 585 } 586 587 sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL")); 588 if(util_getboolean_s(ssl, WS_FALSE)) { 589 sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert")); 590 sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("Key")); 591 sstr_t chain = cfg_directivelist_get_str(obj->directives, S("CertChain")); 592 sstr_t disableprot = cfg_directivelist_get_str( 593 obj->directives, 594 S("SSLDisableProtocol")); 595 596 WSBool config_ok = WS_TRUE; 597 // TODO: log error 598 if(!cert.ptr && !chain.ptr) { 599 log_ereport( 600 LOG_MISCONFIG, 601 "SSL Listener %s: Missing Cert or ChainCert directive", 602 lc.name.ptr); 603 config_ok = WS_FALSE; 604 } 605 if(!privkey.ptr) { 606 log_ereport( 607 LOG_MISCONFIG, 608 "SSL Listener %s: Missing Key directive", 609 lc.name.ptr); 610 config_ok = WS_FALSE; 611 } 612 613 if(config_ok) { 614 lc.certfile = cert; 615 lc.privkeyfile = privkey; 616 lc.chainfile = chain; 617 lc.disable_proto = disableprot; 618 lc.ssl = WS_TRUE; 619 } 620 } else { 621 lc.ssl = WS_FALSE; 622 } 623 624 // TODO: check if all important configs are set 625 626 HttpListener *listener = http_listener_create(&lc); 627 if(!listener) { 628 return 1; 629 } 630 631 listener->default_vs.vs_name = lc.vs.ptr; 632 cfg->listeners = ucx_list_append(cfg->listeners, listener); 633 634 return 0; 635 } 636 637 int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) { 638 VirtualServer *vs = vs_new(); 639 640 vs->name = sstrdup(cfg_directivelist_get_str( 641 obj->directives, 642 sstr("Name"))); 643 vs->host = sstrdup(cfg_directivelist_get_str( 644 obj->directives, 645 sstr("Host"))); 646 vs->document_root = sstrdup(cfg_directivelist_get_str( 647 obj->directives, 648 sstr("DocRoot"))); 649 sstr_t objfile = cfg_directivelist_get_str( 650 obj->directives, 651 sstr("ObjectFile")); 652 sstr_t aclfile = cfg_directivelist_get_str( 653 obj->directives, 654 sstr("ACLFile")); 655 656 // load the object config file 657 sstr_t base = sstr("config/"); 658 sstr_t file = sstrcat(2, base, objfile); 659 file = sstrcat(2, base, objfile); 660 661 // the file is managed by the configuration manager 662 ConfigFile *f = cfgmgr_get_file(file); 663 if(f == NULL) { 664 f = malloc(sizeof(ConfigFile)); 665 f->data = NULL; 666 f->file = sstrdup(file); 667 f->reload = object_conf_reload; 668 f->last_modified = 0; 669 //f->reload(f, cfg); 670 if(cfgmgr_reload_file(f, cfg, NULL)) { 671 free(f->file.ptr); 672 free(f); 673 674 free(file.ptr); 675 return -1; 676 } 677 cfgmgr_attach_file(f); 678 } 679 vs->objectfile = sstrdup(file); 680 vs->objects = (HTTPObjectConfig*)f->data; 681 free(file.ptr); 682 683 684 // load acl config file 685 file = sstrcat(2, base, aclfile); 686 687 ConfigFile *aclf = cfgmgr_get_file(file); 688 if(aclf == NULL) { 689 aclf = malloc(sizeof(ConfigFile)); 690 aclf->data = NULL; 691 aclf->file = sstrdup(file); 692 aclf->reload = acl_conf_reload; 693 aclf->last_modified = 0; 694 //aclf->reload(aclf, cfg); 695 if(cfgmgr_reload_file(aclf, cfg, NULL)) { 696 free(aclf->file.ptr); 697 free(aclf); 698 699 free(file.ptr); 700 return -1; 701 } 702 cfgmgr_attach_file(aclf); 703 } 704 vs->acls = aclf->data; 705 free(file.ptr); 706 707 // set the access log for the virtual server 708 // TODO: don't use always the default 709 vs->log = cfg->default_log; 710 711 ucx_map_sstr_put(cfg->host_vs, vs->host, vs); 712 713 return 0; 714 } 715 716 717 int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { 718 HTTPObjectConfig *old_conf = file->data; 719 file->data = load_obj_conf(file->file.ptr); 720 if(old_conf) { 721 object_conf_unref(old_conf); 722 } 723 if(file->data) { 724 return 0; 725 } else { 726 return 1; 727 } 728 } 729 730 void object_conf_ref(HTTPObjectConfig *conf) { 731 if(conf) { 732 ws_atomic_inc32(&conf->ref); 733 } 734 } 735 736 void object_conf_unref(HTTPObjectConfig *conf) { 737 uint32_t ref = ws_atomic_dec32(&conf->ref); 738 if(ref == 0) { 739 printf("free HTTPObjectConfig %""\n"PRIxPTR, (intptr_t)conf); 740 pool_destroy(conf->pool); 741 } 742 } 743 744 HTTPObjectConfig* load_obj_conf(char *file) { 745 log_ereport(LOG_VERBOSE, "load_obj_conf"); 746 747 // new conf function test 748 ObjectConfig *cfg = load_object_config(file); 749 UcxAllocator *mp = cfg->parser.mp; 750 if(cfg == NULL) { 751 return NULL; 752 } 753 754 // create object config 755 pool_handle_t *pool = pool_create(); 756 HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1); 757 conf->pool = pool; 758 759 // convert ObjectConfig to HTTPObjectConfig 760 761 // add objects 762 conf->nobj = ucx_list_size(cfg->objects); 763 conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); 764 765 UcxList *objlist = cfg->objects; 766 int i = 0; 767 while(objlist != NULL) { 768 ConfigObject *cob = objlist->data; 769 770 // get name and ppath 771 char *name = NULL; 772 char *ppath = NULL; 773 if(cob->name.length > 0) { 774 name = sstrdup_pool(pool, cob->name).ptr; 775 } 776 if(cob->ppath.length > 0) { 777 ppath = sstrdup_pool(pool, cob->ppath).ptr; 778 } 779 780 // create and add object 781 httpd_object *obj = object_new(pool, name); 782 obj->path = NULL; 783 784 conf->objects[i] = obj; 785 786 // add directives 787 for(int j=0;j<NUM_NSAPI_TYPES-1;j++) { 788 UcxList *dirs = cob->directives[j]; 789 while(dirs != NULL) { 790 ConfigDirective *cfgdir = dirs->data; 791 792 directive *d = pool_malloc(pool, sizeof(directive)); 793 if(cfgdir->condition) { 794 sstr_t expr = cfgdir->condition->param_str; 795 d->cond = condition_from_str(pool, expr.ptr, expr.length); 796 } else { 797 d->cond = NULL; 798 } 799 d->param = pblock_create_pool(pool, 8); 800 801 // add params 802 UcxList *param = cfg_param_list(cfgdir->value, mp); 803 while(param != NULL) { 804 ConfigParam *p = param->data; 805 pblock_nvlinsert( 806 p->name.ptr, 807 p->name.length, 808 p->value.ptr, 809 p->value.length, 810 d->param); 811 param = param->next; 812 } 813 814 // get function 815 char *func_name = pblock_findval("fn", d->param); 816 if(!func_name) { 817 log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file); 818 return NULL; 819 } 820 d->func = get_function(func_name); 821 if(!d->func) { 822 log_ereport(LOG_MISCONFIG, "func %s not found", func_name); 823 return NULL; 824 } 825 826 dirs = dirs->next; 827 828 // add function to dtable 829 object_add_directive(obj, d, cfgdir->type_num); 830 } 831 } 832 833 // next 834 i++; 835 objlist = objlist->next; 836 } 837 838 free_object_config(cfg); 839 840 return conf; 841 } 842 843 int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { 844 MimeConfig *mimecfg = load_mime_config(file->file.ptr); 845 MimeMap *old_conf = file->data; 846 847 MimeMap *mimemap = malloc(sizeof(MimeMap)); 848 mimemap->ref = 1; 849 UcxMap *map = ucx_map_new((mimecfg->ntypes * 3) / 2); 850 mimemap->map = map; 851 852 // add ext type pairs 853 UCX_FOREACH(md, mimecfg->directives) { 854 MimeDirective *d = md->data; 855 // add the type for each extension to the map 856 UCX_FOREACH(xl, d->exts) { 857 sstr_t ext = sstr(xl->data); 858 sstr_t value = sstrdup(d->type); 859 ucx_map_sstr_put(map, ext, value.ptr); 860 } 861 } 862 863 file->data = mimemap; 864 865 if(old_conf) { 866 mime_conf_unref(old_conf); 867 } 868 869 free_mime_config(mimecfg); 870 return 0; 871 } 872 873 void mime_conf_ref(MimeMap *conf) { 874 if(conf) { 875 ws_atomic_inc32(&conf->ref); 876 } 877 } 878 879 void mime_conf_unref(MimeMap *conf) { 880 uint32_t ref = ws_atomic_dec32(&conf->ref); 881 if(ref == 0) { 882 printf("free MimeConfig %""\n"PRIxPTR, (intptr_t)conf); 883 UcxMapIterator i = ucx_map_iterator(conf->map); 884 char *str; 885 UCX_MAP_FOREACH(key, str, i) { 886 free(str); 887 } 888 ucx_map_free(conf->map); 889 free(conf); 890 } 891 } 892 893 int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { 894 ACLFile *aclfile = load_acl_file(file->file.ptr); 895 896 ACLData *acldata = acl_data_new(); 897 UCX_FOREACH(elm, aclfile->namedACLs) { 898 ACLConfig *ac = elm->data; 899 ACLList *acl = acl_config_convert(cfg, ac); 900 log_ereport(LOG_VERBOSE, "add acl: %.*s", (int)ac->id.length, ac->id.ptr); 901 ucx_map_sstr_put(acldata->namedACLs, ac->id, acl); 902 } 903 free_acl_file(aclfile); 904 905 ACLData *old_data = file->data; 906 file->data = acldata; 907 if(old_data) { 908 acl_data_unref(old_data); 909 } 910 911 return 0; 912 } 913 914 ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) { 915 WSAcl *acllist = malloc(sizeof(WSAcl)); 916 acllist->acl.check = (acl_check_f)wsacl_check; 917 acllist->acl.authdb = NULL; 918 acllist->acl.authprompt = NULL; 919 acllist->acl.isextern = 0; 920 acllist->ace = NULL; 921 acllist->ece = NULL; 922 923 if(acl->type.ptr && !sstrcmp(acl->type, sstr("fs"))) { 924 acllist->acl.isextern = 1; 925 } 926 927 size_t s = ucx_list_size(acl->entries); 928 WSAce **aces = calloc(s, sizeof(WSAce*)); 929 WSAce **eces = calloc(s, sizeof(WSAce*)); 930 int ai = 0; 931 int ei = 0; 932 933 // convert entries 934 UCX_FOREACH(elm, acl->entries) { 935 ACEConfig *acecfg = elm->data; 936 937 // copy data 938 WSAce *ace = malloc(sizeof(WSAce)); 939 ace->access_mask = acecfg->access_mask; 940 ace->flags = acecfg->flags; 941 ace->type = acecfg->type; 942 ace->who = sstrdup(acecfg->who).ptr; 943 944 // add the entry to the correct array 945 if(ace->type >= ACL_TYPE_AUDIT) { 946 eces[ei] = ace; 947 ei++; 948 } else { 949 aces[ai] = ace; 950 ai++; 951 } 952 } 953 954 // create new entrie arrays with perfect fitting size 955 if(ai > 0) { 956 acllist->ace = calloc(ai, sizeof(WSAce*)); 957 } 958 if(ei > 0) { 959 acllist->ece = calloc(ei, sizeof(WSAce*)); 960 } 961 memcpy(acllist->ace, aces, ai*sizeof(WSAce*)); 962 memcpy(acllist->ece, eces, ei*sizeof(WSAce*)); 963 acllist->acenum = ai; 964 acllist->ecenum = ei; 965 966 free(aces); 967 free(eces); 968 969 // get authentication information 970 if(acl->authparam) { 971 sstr_t authdb_str = cfg_param_get(acl->authparam, sstr("authdb")); 972 sstr_t prompt_str = cfg_param_get(acl->authparam, sstr("prompt")); 973 974 if(authdb_str.ptr) { 975 AuthDB *authdb = ucx_map_sstr_get(cfg->authdbs, authdb_str); 976 acllist->acl.authdb = authdb; 977 if(authdb && prompt_str.ptr) { 978 acllist->acl.authprompt = sstrdup(prompt_str).ptr; 979 } 980 } 981 } 982 983 return &acllist->acl; 984 } 985 986 int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg) { 987 KeyfileConfig *conf = load_keyfile_config(file->file.ptr); 988 if(!conf) { 989 return 1; 990 } 991 992 Keyfile *keyfile = keyfile_new(); 993 994 UCX_FOREACH(elm, conf->users) { 995 KeyfileEntry *user = elm->data; 996 keyfile_add_user( 997 keyfile, 998 user->name, 999 user->hashtype, 1000 user->hashdata, 1001 user->groups, 1002 user->numgroups); 1003 } 1004 1005 free_keyfile_config(conf); 1006 1007 Keyfile *old_data = file->data; 1008 file->data = keyfile; 1009 if(old_data) { 1010 keyfile_unref(old_data); 1011 } 1012 1013 return 0; 1014 } 1015 1016 1017 sstr_t cfg_load_file(sstr_t file) { 1018 sstr_t r; 1019 r.ptr = NULL; 1020 r.length = 0; 1021 1022 if(!file.ptr) { 1023 return r; 1024 } 1025 1026 sstr_t f = sstrdup(file); 1027 FILE *in = fopen(f.ptr, "r"); 1028 if(!in) { 1029 return r; 1030 } 1031 1032 UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); 1033 if(!buf) { 1034 fclose(in); 1035 return r; 1036 } 1037 1038 if(ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write) == 0) { 1039 fclose(in); 1040 ucx_buffer_free(buf); 1041 return r; 1042 } 1043 1044 r.ptr = buf->space; 1045 r.length = buf->pos; 1046 1047 free(buf); 1048 fclose(in); 1049 1050 return r; 1051 } 1052