diff -r 21274e5950af -r a1f4cb076d2f src/server/daemon/config.c --- a/src/server/daemon/config.c Tue Aug 13 22:14:32 2019 +0200 +++ b/src/server/daemon/config.c Sat Sep 24 16:26:10 2022 +0200 @@ -48,6 +48,7 @@ #include "threadpools.h" #include "ldap_auth.h" #include "configmanager.h" +#include "resourcepool.h" #include "vserver.h" #include "../util/pblock.h" @@ -55,10 +56,13 @@ #include "../util/atomic.h" #include "ucx/buffer.h" -pool_handle_t *cfg_pool; +pool_handle_t *init_pool; -// TODO: Funktion für ConfigDirective -> directive -// TODO: Funktion für UcxList parameter list -> pblock +char* cfg_config_file_path(const char *file) { + sstr_t base = ST("config/"); + sstr_t path = sstrcat(2, base, scstr(file)); + return path.ptr; +} int load_init_conf(char *file) { log_ereport(LOG_VERBOSE, "load_init_conf"); @@ -70,14 +74,14 @@ } UcxAllocator *mp = cfg->parser.mp; - cfg_pool = pool_create(); // one pool for one Configuration + init_pool = pool_create(); // one pool for one Configuration UcxList *dirs = cfg->directives; while(dirs != NULL) { ConfigDirective *dir = dirs->data; /* create NSAPI directive */ directive *d = malloc(sizeof(directive)); - d->param = pblock_create_pool(cfg_pool, 8); + d->param = pblock_create_pool(init_pool, 8); UcxList *param = cfg_param_list(dir->value, mp); while(param != NULL) { ConfigParam *p = param->data; @@ -127,19 +131,34 @@ return 0; } -ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file) { +ServerConfiguration* load_server_conf(char *file) { log_ereport(LOG_VERBOSE, "load_server_conf"); - ServerConfig *serverconf = load_server_config(file); - if(serverconf == NULL) { + ServerConfig *serverconf = serverconfig_load(file); + if(!serverconf) { log_ereport(LOG_FAILURE, "Cannot load server.conf"); + return NULL; } - ServerConfiguration *serverconfig = calloc(1, sizeof(ServerConfiguration)); + + pool_handle_t *pool = pool_create(); + + + ServerConfiguration *serverconfig = pool_calloc(pool, 1, sizeof(ServerConfiguration)); serverconfig->ref = 1; - serverconfig->pool = pool_create(); + serverconfig->pool = pool; + + UcxAllocator allocator = util_pool_allocator(serverconfig->pool); + serverconfig->a = pool_malloc(pool, sizeof(UcxAllocator)); + *serverconfig->a = allocator; + serverconfig->listeners = NULL; - serverconfig->host_vs = ucx_map_new(16); - serverconfig->authdbs = ucx_map_new(16); + serverconfig->host_vs = ucx_map_new_a(&allocator, 16); + serverconfig->authdbs = ucx_map_new_a(&allocator, 16); + serverconfig->resources = ucx_map_new_a(&allocator, 16); + serverconfig->dav = ucx_map_new_a(&allocator, 16); + + + // TODO: init serverconfig stuff @@ -161,49 +180,54 @@ */ // init logfile first - UcxList *lfl = ucx_map_sstr_get(serverconf->objects, sstrn("LogFile", 7)); - if(lfl != NULL) { - ServerConfigObject *logobj = lfl->data; - if(logobj == NULL) { + UcxList *list = NULL; + + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("LogFile")); + if(list) { + ConfigNode *logobj = list->data; + if(!logobj) { // error - return NULL; + return NULL; // TODO: fix memory leak } int ret = cfg_handle_logfile(serverconfig, logobj); if(ret != 0) { // cannot initialize log file - return NULL; + return NULL; // TODO: fix memory leak } } else { // horrible error return NULL; } + ucx_list_free(list); - UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Runtime")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; - if(cfg_handle_runtime(serverconfig, scfgobj)) { + ConfigNode *runtimeobj = elm->data; + if(cfg_handle_runtime(serverconfig, runtimeobj)) { // error return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Threadpool")); UCX_FOREACH(elm, list) { if(cfg_handle_threadpool(serverconfig, elm->data)) { return NULL; } } + ucx_list_free(list); // check thread pool config if(check_thread_pool_cfg() != 0) { /* critical error */ return NULL; } - list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("EventHandler")); UCX_FOREACH(elm, list) { if(cfg_handle_eventhandler( - serverconfig, (ServerConfigObject*)elm->data)) { + serverconfig, elm->data)) { // error return NULL; } @@ -213,39 +237,59 @@ /* critical error */ return NULL; } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AccessLog")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; + ConfigNode *scfgobj = elm->data; if(cfg_handle_accesslog(serverconfig, scfgobj)) { return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AuthDB")); + UCX_FOREACH(elm, list) { + ConfigNode *scfgobj = elm->data; + if(cfg_handle_authdb(serverconfig, scfgobj)) { + return NULL; + } + } + ucx_list_free(list); + + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Listener")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; - if(cfg_handle_authdb(serverconfig, scfgobj)) { + ConfigNode *scfgobj = elm->data; + if(cfg_handle_listener(serverconfig, scfgobj)) { + return NULL; + } + } + ucx_list_free(list); + + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("VirtualServer")); + UCX_FOREACH(elm, list) { + ConfigNode *scfgobj = elm->data; + if(cfg_handle_vs(serverconfig, scfgobj)) { + return NULL; + } + } + ucx_list_free(list); + + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("ResourcePool")); + UCX_FOREACH(elm, list) { + ConfigNode *scfgobj = elm->data; + if(cfg_handle_resourcepool(serverconfig, scfgobj)) { return NULL; } } - list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Dav")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; - if(cfg_handle_listener(serverconfig, scfgobj)) { + ConfigNode *scfgobj = elm->data; + if(cfg_handle_dav(serverconfig, scfgobj)) { return NULL; } } - - list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13)); - UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; - if(cfg_handle_vs(serverconfig, scfgobj)) { - return NULL; - } - } - // set VirtualServer for all listeners UcxList *ls = serverconfig->listeners; @@ -268,7 +312,8 @@ ls = ls->next; } - free_server_config(serverconf); + serverconfig_free(serverconf); + return serverconfig; } @@ -279,8 +324,7 @@ void cfg_unref(ServerConfiguration *cfg) { uint32_t ref = ws_atomic_dec32(&cfg->ref); if(ref == 0) { - // TODO: free configuration - printf("free ServerConfiguration %"PRIxPTR"\n", (intptr_t)cfg); + pool_destroy(cfg->pool); } } @@ -289,53 +333,36 @@ } -int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User")); +int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t user = serverconfig_directive_value(obj, SC("User")); if(user.ptr) { - cfg->user = sstrdup_pool(cfg->pool, user); + cfg->user = sstrdup_a(cfg->a, user); } - sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp")); + scstr_t tmp = serverconfig_directive_value(obj, SC("Temp")); if(tmp.ptr) { - cfg->tmp = sstrdup_pool(cfg->pool, tmp); + cfg->tmp = sstrdup_a(cfg->a, tmp); } else { + // TODO: do this check after all config loading is done log_ereport(LOG_MISCONFIG, "no temporary directory specified"); return -1; } // mime file - sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile")); - sstr_t base = sstr("config/"); + scstr_t mf = serverconfig_directive_value(obj, SC("MimeFile")); + scstr_t base = SC("config/"); sstr_t file = sstrcat(2, base, mf); - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = mime_conf_reload; - f->last_modified = 0; - - // load the file content - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(f); + if(mime_conf_load(cfg, file)) { + return -1; } - cfg->mimetypes = f->data; - free(file.ptr); return 0; } -int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); - sstr_t lvl = cfg_directivelist_get_str(obj->directives, sstr("Level")); +int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t file = serverconfig_directive_value(obj, SC("File")); + scstr_t lvl = serverconfig_directive_value(obj, SC("Level")); if(file.ptr == NULL || lvl.ptr == NULL) { /* missing log file parameters */ @@ -343,21 +370,18 @@ } LogConfig logcfg; - logcfg.file = sstrdup(file).ptr; - logcfg.level = sstrdup(lvl).ptr; + logcfg.file = file.ptr; + logcfg.level = lvl.ptr; logcfg.log_stdout = 0; logcfg.log_stderr = 0; /* TODO: stdout, stderr config */ int ret = init_log_file(&logcfg); - - free(logcfg.file); - free(logcfg.level); return ret; } -int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj) { ThreadPoolConfig poolcfg; poolcfg.min_threads = 4; poolcfg.min_threads = 4; @@ -365,21 +389,11 @@ poolcfg.queue_size = 64; poolcfg.stack_size = 262144; - sstr_t name = cfg_directivelist_get_str( - obj->directives, - sstr("Name")); - sstr_t min = cfg_directivelist_get_str( - obj->directives, - sstr("MinThreads")); - sstr_t max = cfg_directivelist_get_str( - obj->directives, - sstr("MaxThreads")); - sstr_t stack = cfg_directivelist_get_str( - obj->directives, - sstr("StackSize")); - sstr_t queue = cfg_directivelist_get_str( - obj->directives, - sstr("QueueSize")); + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t min = serverconfig_directive_value(obj, SC("MinThreads")); + scstr_t max = serverconfig_directive_value(obj, SC("MaxThreads")); + scstr_t stack = serverconfig_directive_value(obj, SC("StackSize")); + scstr_t queue = serverconfig_directive_value(obj, SC("QueueSize")); // TODO: Type if(name.length == 0) { @@ -388,27 +402,41 @@ } if(min.length != 0) { - min = sstrdup(min); - poolcfg.min_threads = atoi(min.ptr); - free(min.ptr); + int64_t value; + if(util_strtoint(min.ptr, &value)) { + poolcfg.min_threads = value; + } else { + log_ereport(LOG_MISCONFIG, "Threadpool: MinThreads not an integer"); + return 1; + } } if(max.length != 0) { - max = sstrdup(max); - poolcfg.max_threads = atoi(max.ptr); - free(max.ptr); + int64_t value; + if(util_strtoint(max.ptr, &value)) { + poolcfg.max_threads = value; + } else { + log_ereport(LOG_MISCONFIG, "Threadpool: MaxThreads not an integer"); + return 1; + } } if(stack.length != 0) { - stack = sstrdup(stack); - poolcfg.stack_size = atoi(stack.ptr); - free(stack.ptr); + int64_t value; + if(util_strtoint(stack.ptr, &value)) { + poolcfg.stack_size = value; + } else { + log_ereport(LOG_MISCONFIG, "Threadpool: StackSize not an integer"); + } } if(queue.length != 0) { - queue = sstrdup(queue); - poolcfg.queue_size = atoi(queue.ptr); - free(queue.ptr); + int64_t value; + if(util_strtoint(queue.ptr, &value)) { + poolcfg.queue_size = value; + } else { + log_ereport(LOG_MISCONFIG, "Threadpool: QueueSize not an integer"); + } } create_threadpool(name, &poolcfg); @@ -416,32 +444,49 @@ return 0; } -int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) { +#define EV_MAX_THREADS 2048 +int cfg_handle_eventhandler(ServerConfiguration *c, ConfigNode *obj) { EventHandlerConfig evcfg; - sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); - sstr_t threads = cfg_directivelist_get_str( - obj->directives, - sstr("Threads")); - sstr_t isdefault = cfg_directivelist_get_str( - obj->directives, - sstr("Default")); + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t threads = serverconfig_directive_value(obj, SC("Threads")); + scstr_t isdefault = serverconfig_directive_value(obj, SC("Default")); evcfg.name = name; - sstr_t s = sstrdup(threads); - evcfg.nthreads = atoi(s.ptr); - free(s.ptr); + int64_t value; + if(!util_strtoint(threads.ptr, &value)) { + log_ereport(LOG_MISCONFIG, "EventHandler: Threads: '%s' is not an integer", threads.ptr); + return 1; + } + if(value < 1 || value > EV_MAX_THREADS) { + log_ereport(LOG_MISCONFIG, "EventHandler: Invalid number of threads (1 .. %d)", EV_MAX_THREADS); + return 1; + } + + evcfg.nthreads = value; evcfg.isdefault = util_getboolean(isdefault.ptr, 0); return create_event_handler(&evcfg); } -int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_resourcepool(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t type = serverconfig_directive_value(obj, SC("Type")); + + int ret = 0; + if(resourcepool_new(cfg, type, name, obj)) { + ret = 1; + } + + return ret; +} + +int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj) { // TODO: use a name to identify the log file - sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); + scstr_t file = serverconfig_directive_value(obj, SC("File")); if(file.ptr == NULL) { return 0; } @@ -456,10 +501,10 @@ return 0; } AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog)); - log->file = sstrdup_pool(cfg->pool, file); + log->file = sstrdup_a(cfg->a, file); log->format = format; log->log = log_file; - cfg->logfiles = ucx_list_append(cfg->logfiles, log); + cfg->logfiles = ucx_list_append_a(cfg->a, cfg->logfiles, log); if(!cfg->default_log) { cfg->default_log = log; @@ -468,61 +513,31 @@ return 0; } -int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); - sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type")); +int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t type = serverconfig_directive_value(obj, SC("Type")); + + AuthDB *authdb = NULL; if(!sstrcmp(type, sstr("ldap"))) { LDAPConfig conf; - sstr_t host = cfg_directivelist_get_str( - obj->directives, - sstr("Host")); - sstr_t port = cfg_directivelist_get_str( - obj->directives, - sstr("Port")); - sstr_t basedn = cfg_directivelist_get_str( - obj->directives, - sstr("BaseDN")); - sstr_t binddn = cfg_directivelist_get_str( - obj->directives, - sstr("BindDN")); - sstr_t basepw = cfg_directivelist_get_str( - obj->directives, - sstr("BindPW")); - - host = sstrdup(host); - port = sstrdup(port); - basedn = sstrdup(basedn); - binddn = sstrdup(binddn); - basepw = sstrdup(basepw); + scstr_t host = serverconfig_directive_value(obj, SC("Host")); + scstr_t port = serverconfig_directive_value( obj, SC("Port")); + scstr_t basedn = serverconfig_directive_value(obj, SC("BaseDN")); + scstr_t binddn = serverconfig_directive_value(obj, SC("BindDN")); + scstr_t basepw = serverconfig_directive_value(obj, SC("BindPW")); - conf.hostname = host.ptr; + conf.hostname = sstrdup_a(cfg->a, host).ptr; conf.port = atoi(port.ptr); - conf.basedn = basedn.ptr; - conf.binddn = binddn.ptr; - conf.bindpw = basepw.ptr; - - name = sstrdup(name); - - AuthDB *authdb = create_ldap_authdb(name.ptr, &conf); - ucx_map_sstr_put(cfg->authdbs, name, authdb); + conf.basedn = sstrdup_a(cfg->a, basedn).ptr; + conf.binddn = sstrdup_a(cfg->a, binddn).ptr; + conf.bindpw = sstrdup_a(cfg->a, basepw).ptr; - // TODO: create_ldap_authdb should copy the strings - /* - free(host.ptr); - free(port.ptr); - free(basedn.ptr); - free(binddn.ptr); - free(basepw.ptr); - free(name.ptr); - */ - + authdb = create_ldap_authdb(cfg, name.ptr, &conf); } else if(!sstrcmp(type, sstr("keyfile"))) { // we only need the file parameter - sstr_t file = cfg_directivelist_get_str( - obj->directives, - sstr("File")); + scstr_t file = serverconfig_directive_value(obj, SC("File")); if(file.length == 0) { log_ereport( LOG_MISCONFIG, @@ -531,67 +546,55 @@ } // load keyfile - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = keyfile_reload; - f->last_modified = 0; - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - return -1; - } - cfgmgr_attach_file(f); - } - - // add keyfile authdb - Keyfile *keyfile = f->data; - keyfile->authdb.name = sstrdup(name).ptr; - ucx_map_sstr_put(cfg->authdbs, name, keyfile); + authdb = keyfile_load(cfg, file); } + if(authdb) { + if(ucx_map_sstr_put(cfg->authdbs, name, authdb)) { + return -1; + } + } + return 0; } -int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj) { ListenerConfig lc; ZERO(&lc, sizeof(ListenerConfig)); lc.cfg = cfg; lc.port = 8080; lc.nacceptors = 1; + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t port = serverconfig_directive_value(obj, SC("Port")); + scstr_t vs = serverconfig_directive_value(obj, SC("DefaultVS")); + scstr_t thrp = serverconfig_directive_value(obj, SC("Threadpool")); + scstr_t blck = serverconfig_directive_value(obj, SC("BlockingIO")); + // TODO: use sstrdup_pool? - lc.name = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Name"))); - lc.port = atoi(cfg_directivelist_get_str( - obj->directives, - sstr("Port")).ptr); - lc.vs = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("DefaultVS"))); - lc.threadpool = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Threadpool"))); - - sstr_t blockingio = cfg_directivelist_get_str( - obj->directives, - sstr("BlockingIO")); - if(blockingio.ptr) { - lc.blockingio = util_getboolean_s(blockingio, WS_FALSE); + int64_t port_value; + if(!util_strtoint(port.ptr, &port_value)) { + log_ereport(LOG_MISCONFIG, "Listener: Invalid argument for parameter 'Port': '%s'", port.ptr); + return 1; + } + if(port_value < 1 || port_value > 65535) { + log_ereport(LOG_MISCONFIG, "Listener: Port number out of range (1 .. 65535)"); + return 1; } - sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL")); + lc.name = sstrdup(name); + lc.port = port_value; + lc.vs = sstrdup(vs); + lc.threadpool = sstrdup(thrp); + + lc.blockingio = util_getboolean_s(blck, WS_FALSE); + + scstr_t ssl = serverconfig_directive_value(obj, SC("SSL")); if(util_getboolean_s(ssl, WS_FALSE)) { - sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert")); - sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("Key")); - sstr_t chain = cfg_directivelist_get_str(obj->directives, S("CertChain")); - sstr_t disableprot = cfg_directivelist_get_str( - obj->directives, - S("SSLDisableProtocol")); + scstr_t cert = serverconfig_directive_value(obj, SC("Cert")); + scstr_t privkey = serverconfig_directive_value(obj, SC("Key")); + scstr_t chain = serverconfig_directive_value(obj, SC("CertChain")); + scstr_t disableprot = serverconfig_directive_value(obj, SC("SSLDisableProtocol")); WSBool config_ok = WS_TRUE; // TODO: log error @@ -628,84 +631,50 @@ return 1; } - listener->default_vs.vs_name = lc.vs.ptr; - cfg->listeners = ucx_list_append(cfg->listeners, listener); + listener->default_vs.vs_name = sstrdup_a(cfg->a, lc.vs).ptr; + cfg->listeners = ucx_list_append_a(cfg->a, cfg->listeners, listener); return 0; } -int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj) { VirtualServer *vs = vs_new(); - vs->name = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Name"))); - vs->host = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Host"))); - vs->document_root = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("DocRoot"))); - sstr_t objfile = cfg_directivelist_get_str( - obj->directives, - sstr("ObjectFile")); - sstr_t aclfile = cfg_directivelist_get_str( - obj->directives, - sstr("ACLFile")); + vs->name = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Name"))); + vs->host = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Host"))); + vs->document_root = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("DocRoot"))); + + scstr_t objfile = serverconfig_directive_value(obj, SC("ObjectFile")); + scstr_t aclfile = serverconfig_directive_value(obj, SC("ACLFile")); // load the object config file sstr_t base = sstr("config/"); sstr_t file = sstrcat(2, base, objfile); - file = sstrcat(2, base, objfile); + // sstrcat with allocator because we want to keep the string + file = sstrcat_a(cfg->a, 2, base, objfile); - // the file is managed by the configuration manager - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = object_conf_reload; - f->last_modified = 0; - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(f); + HTTPObjectConfig *httpobj = objconf_load(cfg, file); + if(!httpobj) { + return -1; } - vs->objectfile = sstrdup(file); - vs->objects = (HTTPObjectConfig*)f->data; - free(file.ptr); + vs->objectfile = file; + vs->objects = httpobj; // load acl config file file = sstrcat(2, base, aclfile); - ConfigFile *aclf = cfgmgr_get_file(file); - if(aclf == NULL) { - aclf = malloc(sizeof(ConfigFile)); - aclf->data = NULL; - aclf->file = sstrdup(file); - aclf->reload = acl_conf_reload; - aclf->last_modified = 0; - //aclf->reload(aclf, cfg); - if(cfgmgr_reload_file(aclf, cfg, NULL)) { - free(aclf->file.ptr); - free(aclf); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(aclf); + ACLData *acldata = acl_conf_load(cfg, file); + if(!acldata) { + return -1; } - vs->acls = aclf->data; + vs->acls = acldata; + free(file.ptr); + // set the access log for the virtual server - // TODO: don't use always the default + // TODO: don't always use the default vs->log = cfg->default_log; ucx_map_sstr_put(cfg->host_vs, vs->host, vs); @@ -713,54 +682,130 @@ return 0; } - -int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - HTTPObjectConfig *old_conf = file->data; - file->data = load_obj_conf(file->file.ptr); - if(old_conf) { - object_conf_unref(old_conf); +int cfg_handle_dav(ServerConfiguration *cfg, ConfigNode *obj) { + UcxList *backends = NULL; // list of ConfigArg* + UcxAllocator a = util_pool_allocator(cfg->pool); + int init_error; + + // parse args + char *uri = NULL; + char *ppath = NULL; + char *name = NULL; + UCX_FOREACH(elm, obj->args) { + ConfigArg *arg = elm->data; + if(arg->name.ptr == NULL) { + // default: uri + uri = arg->value.ptr; + } else if(!sstrcasecmp(arg->name, SC("uri"))) { + uri = arg->value.ptr; + } else if(!sstrcasecmp(arg->name, SC("ppath"))) { + ppath = arg->value.ptr; + } else if(!sstrcasecmp(arg->name, SC("name"))) { + name = arg->value.ptr; + } } - if(file->data) { - return 0; - } else { + if(!uri && !ppath && !name) { return 1; } -} - -void object_conf_ref(HTTPObjectConfig *conf) { - if(conf) { - ws_atomic_inc32(&conf->ref); + + // get a list of all DavBackends + UCX_FOREACH(elm, obj->children) { + ConfigNode *node = elm->data; + if(!sstrcasecmp(node->name, SC("DavBackend"))) { + if(node->type == CONFIG_NODE_DIRECTIVE) { + if(ucx_list_size(node->args) == 1) { + ConfigArg *arg = node->args->data; + backends = ucx_list_append(backends, arg); + } else { + log_ereport(LOG_MISCONFIG, "DavBackend must have only one value"); + ucx_list_free(backends); + return 1; + } + } else { + log_ereport(LOG_MISCONFIG, "DavBackend must be a directive"); + ucx_list_free(backends); + return 1; + } + } } + + int ret = 0; + WebdavRepository *repository = pool_malloc(cfg->pool, sizeof(WebdavRepository)); + repository->vfs = NULL; + repository->vfsInitData = NULL; + repository->davBackends = NULL; + + // initialize backends + UCX_FOREACH(elm, backends) { + // the DavBackend value should contain the dav class name + ConfigArg *backendArg = elm->data; + + WebdavType *dav = webdav_get_type((scstr_t){backendArg->value.ptr, backendArg->value.length}); + if(!dav) { + log_ereport(LOG_MISCONFIG, "Unknown webdav backend type '%s'", backendArg->value.ptr); + ret = 1; + break; + } + + // call backend init + // init_data can be NULL, errors will be indicated by init_error + void *init_data = webdav_init_backend(cfg, cfg->pool, dav, obj, &init_error); + if(init_error) { + log_ereport(LOG_FAILURE, "Failed to initialize webdav backend %s", backendArg->value.ptr); + ret = 1; + break; + } + + WebdavBackendInitData *davInit = pool_malloc(cfg->pool, sizeof(WebdavBackendInitData)); + if(!davInit) { + log_ereport(LOG_FAILURE, "Failed to initialize webdav backend %s: OOM", backendArg->value.ptr); + ret = 1; + break; + } + davInit->davType = dav; + davInit->davInitData = init_data; + + repository->davBackends = ucx_list_append_a(&a, repository->davBackends, davInit); + } + + // initialize vfs + scstr_t vfs_class = serverconfig_directive_value(obj, SC("VFS")); + if(vfs_class.length > 0) { + VfsType *vfs = vfs_get_type((scstr_t){vfs_class.ptr, vfs_class.length}); + if(vfs) { + repository->vfs = vfs; + repository->vfsInitData = vfs_init_backend(cfg, cfg->pool, vfs, obj, &init_error); + ret = init_error; + } else { + log_ereport(LOG_FAILURE, "Unknown vfs type '%s'", vfs_class.ptr); + ret = 1; + } + } + + scstr_t object = serverconfig_directive_value(obj, SC("Object")); + if(object.length > 0) { + repository->object = sstrdup_a(&a, object); + if(repository->object.length != object.length) { + // OOM + log_ereport(LOG_FAILURE, "Cannot create webdav repository: OOM"); + ret = 1; + } + } + + if(!ret) { + if(name) { + ucx_map_cstr_put(cfg->dav, name, repository); + } else { + log_ereport(LOG_FAILURE, "TODO: location based dav repositories not implemented"); + ret = 1; + } + } + + return ret; } -void object_conf_unref(HTTPObjectConfig *conf) { - uint32_t ref = ws_atomic_dec32(&conf->ref); - if(ref == 0) { - printf("free HTTPObjectConfig %"PRIxPTR"\n", (intptr_t)conf); - pool_destroy(conf->pool); - } -} - -HTTPObjectConfig* load_obj_conf(char *file) { - log_ereport(LOG_VERBOSE, "load_obj_conf"); - - // new conf function test - ObjectConfig *cfg = load_object_config(file); - UcxAllocator *mp = cfg->parser.mp; - if(cfg == NULL) { - return NULL; - } - - // create object config - pool_handle_t *pool = pool_create(); - HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1); - conf->pool = pool; - - // convert ObjectConfig to HTTPObjectConfig - - // add objects - conf->nobj = ucx_list_size(cfg->objects); - conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); +static int convert_objconf(ServerConfiguration *scfg, ObjectConfig *cfg, HTTPObjectConfig *conf, sstr_t file) { + pool_handle_t *pool = conf->pool; UcxList *objlist = cfg->objects; int i = 0; @@ -772,13 +817,16 @@ char *ppath = NULL; if(cob->name.length > 0) { name = sstrdup_pool(pool, cob->name).ptr; + if(!name) return -1; } if(cob->ppath.length > 0) { ppath = sstrdup_pool(pool, cob->ppath).ptr; + if(!ppath) return -1; } // create and add object httpd_object *obj = object_new(pool, name); + if(!obj) return -1; obj->path = NULL; conf->objects[i] = obj; @@ -788,8 +836,9 @@ UcxList *dirs = cob->directives[j]; while(dirs != NULL) { ConfigDirective *cfgdir = dirs->data; - + directive *d = pool_malloc(pool, sizeof(directive)); + if(!d) return -1; if(cfgdir->condition) { sstr_t expr = cfgdir->condition->param_str; d->cond = condition_from_str(pool, expr.ptr, expr.length); @@ -799,7 +848,7 @@ d->param = pblock_create_pool(pool, 8); // add params - UcxList *param = cfg_param_list(cfgdir->value, mp); + UcxList *param = cfg_param_list(cfgdir->value, scfg->a); while(param != NULL) { ConfigParam *p = param->data; pblock_nvlinsert( @@ -814,13 +863,13 @@ // get function char *func_name = pblock_findval("fn", d->param); if(!func_name) { - log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file); - return NULL; + log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file.ptr); + return -1; } d->func = get_function(func_name); if(!d->func) { log_ereport(LOG_MISCONFIG, "func %s not found", func_name); - return NULL; + return -1; } dirs = dirs->next; @@ -834,66 +883,94 @@ i++; objlist = objlist->next; } + + return 0; +} + +HTTPObjectConfig* objconf_load(ServerConfiguration *scfg, sstr_t file) { + log_ereport(LOG_VERBOSE, "load_obj_conf"); + + int ret = 0; + + // create object config + pool_handle_t *pool = scfg->pool; + HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1); + if(!conf) { + return NULL; + } + conf->pool = pool; + + // load obj config file + ObjectConfig *cfg = load_object_config(file.ptr); + if(!cfg) { + return NULL; + } + + // convert ObjectConfig to HTTPObjectConfig + + // add objects + conf->nobj = ucx_list_size(cfg->objects); + conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); + if(conf->objects) { + ret = convert_objconf(scfg, cfg, conf, file); + } else { + ret = -1; + } free_object_config(cfg); - return conf; + return !ret ? conf : NULL; } -int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - MimeConfig *mimecfg = load_mime_config(file->file.ptr); - MimeMap *old_conf = file->data; - - MimeMap *mimemap = malloc(sizeof(MimeMap)); - mimemap->ref = 1; - UcxMap *map = ucx_map_new((mimecfg->ntypes * 3) / 2); - mimemap->map = map; - - // add ext type pairs - UCX_FOREACH(md, mimecfg->directives) { - MimeDirective *d = md->data; - // add the type for each extension to the map - UCX_FOREACH(xl, d->exts) { - sstr_t ext = sstr(xl->data); - sstr_t value = sstrdup(d->type); - ucx_map_sstr_put(map, ext, value.ptr); - } +int mime_conf_load(ServerConfiguration *cfg, sstr_t file) { + MimeConfig *mimecfg = load_mime_config(file.ptr); + if(!mimecfg) { + return -1; } - file->data = mimemap; + int ret = 0; + + // cleanup in case of errors is done by the allocator + MimeMap *mimemap = almalloc(cfg->a, sizeof(MimeMap)); + UcxMap *map = ucx_map_new_a(cfg->a, (mimecfg->ntypes * 3) / 2); - if(old_conf) { - mime_conf_unref(old_conf); + if(mimemap && map) { + mimemap->map = map; + + // add ext type pairs + UCX_FOREACH(md, mimecfg->directives) { + MimeDirective *d = md->data; + // add the type for each extension to the map + UCX_FOREACH(xl, d->exts) { + sstr_t ext = sstr(xl->data); + sstr_t value = sstrdup(d->type); + if(ucx_map_sstr_put(map, ext, value.ptr)) { + ret = -1; + break; + } + } + if(ret) { + break; + } + } + + cfg->mimetypes = mimemap; + } else { + ret = -1; } free_mime_config(mimecfg); - return 0; -} - -void mime_conf_ref(MimeMap *conf) { - if(conf) { - ws_atomic_inc32(&conf->ref); - } + return ret; } -void mime_conf_unref(MimeMap *conf) { - uint32_t ref = ws_atomic_dec32(&conf->ref); - if(ref == 0) { - printf("free MimeConfig %"PRIxPTR"\n", (intptr_t)conf); - UcxMapIterator i = ucx_map_iterator(conf->map); - char *str; - UCX_MAP_FOREACH(key, str, i) { - free(str); - } - ucx_map_free(conf->map); - free(conf); - } -} + -int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - ACLFile *aclfile = load_acl_file(file->file.ptr); +ACLData* acl_conf_load(ServerConfiguration *cfg, sstr_t file) { + ACLFile *aclfile = load_acl_file(file.ptr); - ACLData *acldata = acl_data_new(); + // TODO: malloc return checks + + ACLData *acldata = acl_data_new(cfg->a); UCX_FOREACH(elm, aclfile->namedACLs) { ACLConfig *ac = elm->data; ACLList *acl = acl_config_convert(cfg, ac); @@ -902,17 +979,13 @@ } free_acl_file(aclfile); - ACLData *old_data = file->data; - file->data = acldata; - if(old_data) { - acl_data_unref(old_data); - } - - return 0; + return acldata; } ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) { - WSAcl *acllist = malloc(sizeof(WSAcl)); + UcxAllocator *a = cfg->a; + + WSAcl *acllist = almalloc(cfg->a, sizeof(WSAcl)); acllist->acl.check = (acl_check_f)wsacl_check; acllist->acl.authdb = NULL; acllist->acl.authprompt = NULL; @@ -925,8 +998,8 @@ } size_t s = ucx_list_size(acl->entries); - WSAce **aces = calloc(s, sizeof(WSAce*)); - WSAce **eces = calloc(s, sizeof(WSAce*)); + WSAce **tmp_aces = calloc(s, sizeof(WSAce*)); + WSAce **tmp_eces = calloc(s, sizeof(WSAce*)); int ai = 0; int ei = 0; @@ -935,36 +1008,36 @@ ACEConfig *acecfg = elm->data; // copy data - WSAce *ace = malloc(sizeof(WSAce)); + WSAce *ace = almalloc(a, sizeof(WSAce)); ace->access_mask = acecfg->access_mask; ace->flags = acecfg->flags; ace->type = acecfg->type; - ace->who = sstrdup(acecfg->who).ptr; + ace->who = sstrdup_a(a, acecfg->who).ptr; // add the entry to the correct array if(ace->type >= ACL_TYPE_AUDIT) { - eces[ei] = ace; + tmp_eces[ei] = ace; ei++; } else { - aces[ai] = ace; + tmp_aces[ai] = ace; ai++; } } // create new entrie arrays with perfect fitting size if(ai > 0) { - acllist->ace = calloc(ai, sizeof(WSAce*)); + acllist->ace = alcalloc(a, ai, sizeof(WSAce*)); } if(ei > 0) { - acllist->ece = calloc(ei, sizeof(WSAce*)); + acllist->ece = alcalloc(a, ei, sizeof(WSAce*)); } - memcpy(acllist->ace, aces, ai*sizeof(WSAce*)); - memcpy(acllist->ece, eces, ei*sizeof(WSAce*)); + memcpy(acllist->ace, tmp_aces, ai*sizeof(WSAce*)); + memcpy(acllist->ece, tmp_eces, ei*sizeof(WSAce*)); acllist->acenum = ai; acllist->ecenum = ei; - free(aces); - free(eces); + free(tmp_aces); + free(tmp_eces); // get authentication information if(acl->authparam) { @@ -975,7 +1048,7 @@ AuthDB *authdb = ucx_map_sstr_get(cfg->authdbs, authdb_str); acllist->acl.authdb = authdb; if(authdb && prompt_str.ptr) { - acllist->acl.authprompt = sstrdup(prompt_str).ptr; + acllist->acl.authprompt = sstrdup_a(a, prompt_str).ptr; } } } @@ -983,69 +1056,47 @@ return &acllist->acl; } -int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg) { - KeyfileConfig *conf = load_keyfile_config(file->file.ptr); - if(!conf) { - return 1; +AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file) { + Keyfile *keyfile = keyfile_new(cfg->a); + if(!keyfile) { + return NULL; } - Keyfile *keyfile = keyfile_new(); + KeyfileConfig *conf = load_keyfile_config(file.ptr); + if(!conf) { + return NULL; + } + + AuthDB *ret = &keyfile->authdb; UCX_FOREACH(elm, conf->users) { KeyfileEntry *user = elm->data; - keyfile_add_user( + if(keyfile_add_user( keyfile, user->name, user->hashtype, user->hashdata, user->groups, - user->numgroups); + user->numgroups)) + { + ret = NULL; + break; + } } free_keyfile_config(conf); - Keyfile *old_data = file->data; - file->data = keyfile; - if(old_data) { - keyfile_unref(old_data); - } - - return 0; + return ret; } - -sstr_t cfg_load_file(sstr_t file) { - sstr_t r; - r.ptr = NULL; - r.length = 0; - - if(!file.ptr) { - return r; - } - - sstr_t f = sstrdup(file); - FILE *in = fopen(f.ptr, "r"); - if(!in) { - return r; +pblock* config_obj2pblock(pool_handle_t *pool, ConfigNode *obj) { + pblock *pb = pblock_create_pool(pool, 8); + UCX_FOREACH(elm, obj->children) { + ConfigNode *d = elm->data; + if(d->type == CONFIG_NODE_DIRECTIVE && d->name.length > 0 && ucx_list_size(d->args) == 1) { + ConfigArg *arg = d->args->data; + pblock_nvlinsert(d->name.ptr, d->name.length, arg->value.ptr, arg->value.length, pb); + } } - - UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - if(!buf) { - fclose(in); - return r; - } - - if(ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write) == 0) { - fclose(in); - ucx_buffer_free(buf); - return r; - } - - r.ptr = buf->space; - r.length = buf->pos; - - free(buf); - fclose(in); - - return r; + return pb; }