1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 <cx/string.h>
41 #include <cx/utils.h>
42 #include <cx/hash_map.h>
43 #include <cx/linked_list.h>
44 #include <cx/compare.h>
45
46 #include "httplistener.h"
47 #include "config.h"
48 #include "func.h"
49 #include "log.h"
50 #include "event.h"
51 #include "threadpools.h"
52 #include "ldap_auth.h"
53 #include "configmanager.h"
54 #include "resourcepool.h"
55
56 #include "vserver.h"
57 #include "../util/pblock.h"
58 #include "../util/util.h"
59 #include "../util/atomic.h"
60 #include "cx/buffer.h"
61
62 static pool_handle_t *init_pool;
63
64 pool_handle_t* cfg_get_init_pool(
void) {
65 return init_pool;
66 }
67
68 char* cfg_config_file_path(
const char *file) {
69 cxstring base =
CX_STR(
"config/");
70 cxmutstr path = cx_strcat(
2, base, cx_str(file));
71 return path.ptr;
72 }
73
74 InitConfig* load_init_conf(
const char *file) {
75 log_ereport(
LOG_VERBOSE,
"load_init_conf");
76
77 InitConfig *cfg = initconfig_load(file);
78 if(cfg ==
NULL) {
79 log_ereport(
LOG_FAILURE,
"Cannot load init.conf");
80 return NULL;;
81 }
82
83 return cfg;
84 }
85
86 int apply_init_conf(InitConfig *cfg) {
87 init_pool = pool_create();
88
89 ConfigNode *dir = cfg->root->children_begin;
90 while(dir) {
91 if(dir->type !=
CONFIG_NODE_DIRECTIVE) {
92
93 dir = dir->next;
94 continue;
95 }
96
97
98
99
100
101
102
103 directive *d = pool_malloc(init_pool,
sizeof(directive));
104 d->param = pblock_create_pool(init_pool,
8);
105
106 ConfigParam *param = dir->args;
107 while(param !=
NULL) {
108 pblock_nvlinsert(
109 param->name.ptr,
110 param->name.length,
111 param->value.ptr,
112 param->value.length,
113 d->param);
114
115 param = param->next;
116 }
117
118
119
120 char *func_name = pblock_findval(
"fn", d->param);
121 d->func = get_function(func_name);
122 if(d->func ==
NULL) {
123 log_ereport(
124 LOG_MISCONFIG,
125 "Cannot find Init function %s",
126 func_name);
127 return 1;
128 }
129
130
131 int ret = d->func->func(d->param,
NULL,
NULL);
132 if(ret !=
REQ_PROCEED && ret !=
REQ_NOACTION) {
133 log_ereport(
134 LOG_FAILURE,
135 "Error running Init function %s",
136 func_name);
137 return 1;
138 }
139
140 dir = dir->next;
141 }
142
143 return 0;
144 }
145
146 void free_init_conf(InitConfig *cfg) {
147 initconfig_free(cfg);
148 }
149
150 ServerConfiguration* load_server_conf(CfgManager *mgr,
char *file) {
151 log_ereport(
LOG_VERBOSE,
"load_server_conf");
152
153 ServerConfig *serverconf = serverconfig_load(file);
154 if(!serverconf) {
155 log_ereport(
LOG_FAILURE,
"Cannot load server.conf");
156 return NULL;
157 }
158 mgr->serverconf = serverconf;
159
160 pool_handle_t *pool = pool_create();
161
162
163 ServerConfiguration *serverconfig = pool_calloc(pool,
1,
sizeof(ServerConfiguration));
164 serverconfig->ref =
1;
165 serverconfig->pool = pool;
166
167 CxAllocator *allocator = pool_allocator(serverconfig->pool);
168 serverconfig->a = allocator;
169
170 serverconfig->listeners = cxLinkedListCreate(serverconfig->a,
NULL,
CX_STORE_POINTERS);
171 serverconfig->logfiles = cxLinkedListCreate(serverconfig->a,
NULL,
CX_STORE_POINTERS);
172 serverconfig->host_vs = cxHashMapCreate(serverconfig->a,
CX_STORE_POINTERS,
16);
173 serverconfig->authdbs = cxHashMapCreate(serverconfig->a,
CX_STORE_POINTERS,
16);
174 serverconfig->resources = cxHashMapCreate(serverconfig->a,
CX_STORE_POINTERS,
16);
175 serverconfig->dav = cxHashMapCreate(serverconfig->a,
CX_STORE_POINTERS,
16);
176
177
178
179
180
181
182
183
184
185
186
187 CxList *list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"Runtime"));
188 CxIterator iter = cxListIterator(list);
189 cx_foreach(ConfigNode *, runtimeobj, iter) {
190 if(cfg_handle_runtime(serverconfig, runtimeobj)) {
191
192 log_ereport(
LOG_FAILURE,
"server.conf runtime");
193 return NULL;
194 }
195 }
196 cxListDestroy(list);
197
198
199 log_ereport(
LOG_DEBUG,
"apply config: Threadpool");
200 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"Threadpool"));
201 iter = cxListIterator(list);
202 cx_foreach(ConfigNode *, elm, iter) {
203 if(cfg_handle_threadpool(serverconfig, elm)) {
204 log_ereport(
LOG_FAILURE,
"server.conf threadpool");
205 return NULL;
206 }
207 }
208 cxListDestroy(list);
209
210 if(check_thread_pool_cfg() !=
0) {
211
212 return NULL;
213 }
214
215
216 log_ereport(
LOG_DEBUG,
"apply config: EventHandler");
217 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"EventHandler"));
218 iter = cxListIterator(list);
219 cx_foreach(ConfigNode *, elm, iter) {
220 if(cfg_handle_eventhandler(serverconfig, elm)) {
221
222 log_ereport(
LOG_FAILURE,
"cannot create event handler");
223 return NULL;
224 }
225 }
226
227 if(check_event_handler_cfg() !=
0) {
228
229 return NULL;
230 }
231 cxListDestroy(list);
232
233
234 log_ereport(
LOG_DEBUG,
"apply config: Listener");
235 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"Listener"));
236 iter = cxListIterator(list);
237 cx_foreach(ConfigNode *, scfgobj, iter) {
238 if(cfg_handle_listener(serverconfig, scfgobj)) {
239 return NULL;
240 }
241 }
242 cxListDestroy(list);
243
244
245
246 return serverconfig;
247 }
248
249 ServerConfiguration* apply_server_conf(CfgManager *mgr) {
250 ServerConfig *serverconf = mgr->serverconf;
251 ServerConfiguration *serverconfig = mgr->cfg;
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266 CxList *list;
267
268 log_ereport(
LOG_DEBUG,
"apply config: LogFile");
269 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"LogFile"));
270 CxIterator iter = cxListIterator(list);
271 cx_foreach(ConfigNode *, logobj, iter) {
272 if(!logobj) {
273
274 cxListDestroy(list);
275 return NULL;
276 }
277
278 int ret = cfg_handle_logfile(serverconfig, logobj);
279 if(ret !=
0) {
280
281 cxListDestroy(list);
282 return NULL;
283 }
284 }
285 cxListDestroy(list);
286
287 log_ereport(
LOG_DEBUG,
"apply config: AccessLog");
288 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"AccessLog"));
289 iter = cxListIterator(list);
290 cx_foreach(ConfigNode *, scfgobj, iter) {
291 if(cfg_handle_accesslog(serverconfig, scfgobj)) {
292 return NULL;
293 }
294 }
295 cxListDestroy(list);
296
297 log_ereport(
LOG_DEBUG,
"apply config: AuthDB");
298 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"AuthDB"));
299 iter = cxListIterator(list);
300 cx_foreach(ConfigNode *, scfgobj, iter) {
301 if(cfg_handle_authdb(serverconfig, scfgobj)) {
302 return NULL;
303 }
304 }
305 cxListDestroy(list);
306
307 log_ereport(
LOG_DEBUG,
"apply config: VirtualServer");
308 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"VirtualServer"));
309 iter = cxListIterator(list);
310 cx_foreach(ConfigNode *, scfgobj, iter) {
311 if(cfg_handle_vs(serverconfig, scfgobj)) {
312 return NULL;
313 }
314 }
315 cxListDestroy(list);
316
317 log_ereport(
LOG_DEBUG,
"apply config: ResourcePool");
318 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"ResourcePool"));
319 iter = cxListIterator(list);
320 cx_foreach(ConfigNode *, scfgobj, iter) {
321 if(cfg_handle_resourcepool(serverconfig, scfgobj)) {
322 return NULL;
323 }
324 }
325 cxListDestroy(list);
326
327 log_ereport(
LOG_DEBUG,
"apply config: Dav");
328 list = serverconfig_get_node_list(serverconf->root,
CONFIG_NODE_OBJECT, cx_str(
"Dav"));
329 iter = cxListIterator(list);
330 cx_foreach(ConfigNode *, scfgobj, iter) {
331 if(cfg_handle_dav(serverconfig, scfgobj)) {
332 return NULL;
333 }
334 }
335 cxListDestroy(list);
336
337
338 CxList *ls = serverconfig->listeners;
339 iter = cxListIterator(ls);
340 cx_foreach(HttpListener *, listener, iter) {
341 cxstring vsname = cx_str(listener->default_vs.vs_name);
342
343
344
345 CxIterator map_iter = cxMapIteratorValues(serverconfig->host_vs);
346 cx_foreach(VirtualServer *, vs, map_iter) {
347 if(!cx_strcmp(vsname, (cxstring){vs->name.ptr, vs->name.length})) {
348 listener->default_vs.vs = vs;
349 break;
350 }
351 }
352 }
353
354 serverconfig_free(serverconf);
355
356 return serverconfig;
357 }
358
359 int migrate_server_conf(ServerConfiguration *old_cfg, ServerConfiguration *new_cfg) {
360 old_cfg->next = new_cfg;
361 cfg_ref(new_cfg);
362
363
364
365 CxIterator old_listeners = cxListIterator(old_cfg->listeners);
366 cx_foreach(HttpListener*, oldls, old_listeners) {
367 if(oldls->next) {
368
369 log_ereport(
LOG_WARN,
"migrate_server_conf: oldls->next not NULL");
370 continue;
371 }
372
373 CxIterator new_listeners = cxListIterator(new_cfg->listeners);
374 cx_foreach(HttpListener*, newls, new_listeners) {
375 if(http_listener_socket_eq(oldls, newls)) {
376 http_listener_set_next(oldls, newls);
377 break;
378 }
379 }
380 http_listener_shutdown_acceptors(oldls);
381
382
383 }
384
385 return 0;
386 }
387
388 void cfg_ref(ServerConfiguration *cfg) {
389 ws_atomic_inc32(&cfg->ref);
390 }
391
392 void cfg_unref(ServerConfiguration *cfg) {
393 uint32_t ref = ws_atomic_dec32(&cfg->ref);
394 if(ref ==
0) {
395 if(cfg->next) {
396 cfg_unref(cfg->next);
397 }
398 log_ereport(
LOG_VERBOSE,
"destroy configuration %p", cfg);
399
400 CxIterator i = cxListIterator(cfg->listeners);
401 cx_foreach(HttpListener*, listener, i) {
402 http_listener_destroy(listener);
403 }
404
405 pool_destroy(cfg->pool);
406 }
407 }
408
409
410 void init_server_config_parser() {
411
412 }
413
414 int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj) {
415 cxstring user = serverconfig_object_directive_value(obj, cx_str(
"User"));
416 if(user.ptr) {
417 cfg->user = cx_strdup_a(cfg->a, user);
418 }
419 cxstring tmp = serverconfig_object_directive_value(obj, cx_str(
"Temp"));
420 if(tmp.ptr) {
421 cfg->tmp = cx_strdup_a(cfg->a, tmp);
422 }
else {
423
424 log_ereport(
LOG_MISCONFIG,
"no temporary directory specified");
425 return -
1;
426 }
427
428
429 cxstring mf = serverconfig_object_directive_value(obj, cx_str(
"MimeFile"));
430 cxstring base = cx_str(
"config/");
431 cxmutstr file = cx_strcat(
2, base, mf);
432
433 if(mime_conf_load(cfg, file)) {
434 return -
1;
435 }
436
437 free(file.ptr);
438 return 0;
439 }
440
441 int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj) {
442 cxstring file = serverconfig_object_directive_value(obj, cx_str(
"File"));
443 cxstring lvl = serverconfig_object_directive_value(obj, cx_str(
"Level"));
444
445 int err =
0;
446 if(file.ptr ==
NULL) {
447 err =
1;
448 log_ereport(
LOG_MISCONFIG,
"LogFile: parameter missing: File");
449 }
450 if(lvl.ptr ==
NULL) {
451 err =
1;
452 log_ereport(
LOG_MISCONFIG,
"LogFile: parameter missing: Level");
453 }
454 if(err) {
455 return -
1;
456 }
457
458 LogConfig logcfg;
459 logcfg.file = file.ptr;
460 logcfg.level = lvl.ptr;
461 logcfg.log_stdout =
0;
462 logcfg.log_stderr =
0;
463
464
465 int ret = init_log_file(&logcfg);
466
467 return ret;
468 }
469
470 int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj) {
471 ThreadPoolConfig poolcfg;
472 poolcfg.min_threads =
4;
473 poolcfg.min_threads =
4;
474 poolcfg.max_threads =
8;
475 poolcfg.queue_size =
64;
476 poolcfg.stack_size =
262144;
477
478 cxstring name = serverconfig_object_directive_value(obj, cx_str(
"Name"));
479 cxstring min = serverconfig_object_directive_value(obj, cx_str(
"MinThreads"));
480 cxstring max = serverconfig_object_directive_value(obj, cx_str(
"MaxThreads"));
481 cxstring stack = serverconfig_object_directive_value(obj, cx_str(
"StackSize"));
482 cxstring queue = serverconfig_object_directive_value(obj, cx_str(
"QueueSize"));
483
484
485 if(name.length ==
0) {
486
487 return 1;
488 }
489
490 if(min.length !=
0) {
491 int64_t value;
492 if(util_strtoint(min.ptr, &value)) {
493 poolcfg.min_threads = value;
494 }
else {
495 log_ereport(
LOG_MISCONFIG,
"Threadpool: MinThreads not an integer");
496 return 1;
497 }
498 }
499
500 if(max.length !=
0) {
501 int64_t value;
502 if(util_strtoint(max.ptr, &value)) {
503 poolcfg.max_threads = value;
504 }
else {
505 log_ereport(
LOG_MISCONFIG,
"Threadpool: MaxThreads not an integer");
506 return 1;
507 }
508 }
509
510 if(stack.length !=
0) {
511 int64_t value;
512 if(util_strtoint(stack.ptr, &value)) {
513 poolcfg.stack_size = value;
514 }
else {
515 log_ereport(
LOG_MISCONFIG,
"Threadpool: StackSize not an integer");
516 }
517 }
518
519 if(queue.length !=
0) {
520 int64_t value;
521 if(util_strtoint(queue.ptr, &value)) {
522 poolcfg.queue_size = value;
523 }
else {
524 log_ereport(
LOG_MISCONFIG,
"Threadpool: QueueSize not an integer");
525 }
526 }
527
528 create_threadpool(name, &poolcfg);
529
530 return 0;
531 }
532
533 #define EV_MAX_THREADS 2048
534 int cfg_handle_eventhandler(ServerConfiguration *c, ConfigNode *obj) {
535 EventHandlerConfig evcfg;
536
537 cxstring name = serverconfig_object_directive_value(obj, cx_str(
"Name"));
538 cxstring threads = serverconfig_object_directive_value(obj, cx_str(
"Threads"));
539 cxstring isdefault = serverconfig_object_directive_value(obj, cx_str(
"Default"));
540
541 evcfg.name = name;
542
543 int64_t value;
544 if(!util_strtoint(threads.ptr, &value)) {
545 log_ereport(
LOG_MISCONFIG,
"EventHandler: Threads: ''%s'' is not an integer", threads.ptr);
546 return 1;
547 }
548 if(value <
1 || value >
EV_MAX_THREADS) {
549 log_ereport(
LOG_MISCONFIG,
"EventHandler: Invalid number of threads (1 .. %d)",
EV_MAX_THREADS);
550 return 1;
551 }
552
553 evcfg.nthreads = value;
554
555 evcfg.isdefault = util_getboolean(isdefault.ptr,
0);
556
557 return create_event_handler(&evcfg);
558 }
559
560 int cfg_handle_resourcepool(ServerConfiguration *cfg, ConfigNode *obj) {
561 cxstring name = serverconfig_object_directive_value(obj, cx_str(
"Name"));
562 cxstring type = serverconfig_object_directive_value(obj, cx_str(
"Type"));
563
564 int ret =
0;
565 if(resourcepool_new(cfg, type, name, obj)) {
566 ret =
1;
567 }
568
569 return ret;
570 }
571
572 int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj) {
573
574
575 cxstring file = serverconfig_object_directive_value(obj, cx_str(
"File"));
576 if(file.ptr ==
NULL) {
577 return 0;
578 }
579 cxmutstr format;
580 format.ptr =
NULL;
581 format.length =
0;
582
583
584 LogFile *log_file = get_access_log_file(file);
585 if(!log_file) {
586
587 return 0;
588 }
589 AccessLog *log = pool_malloc(cfg->pool,
sizeof(AccessLog));
590 log->file = cx_strdup_a(cfg->a, file);
591 log->format = format;
592 log->log = log_file;
593 cxListAdd(cfg->logfiles, log);
594
595 if(!cfg->default_log) {
596 cfg->default_log = log;
597 }
598
599 return 0;
600 }
601
602 int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj) {
603 cxstring name = serverconfig_object_directive_value(obj, cx_str(
"Name"));
604 cxstring type = serverconfig_object_directive_value(obj, cx_str(
"Type"));
605
606 AuthDB *authdb =
NULL;
607
608 if(!cx_strcmp(type, cx_str(
"ldap"))) {
609 authdb = create_ldap_authdb(cfg, name.ptr, obj);
610 }
else if(!cx_strcmp(type, cx_str(
"keyfile"))) {
611
612 cxstring file = serverconfig_object_directive_value(obj, cx_str(
"File"));
613 if(file.length ==
0) {
614 log_ereport(
615 LOG_MISCONFIG,
616 "missing File parameter for keyfile authdb");
617 return 1;
618 }
619
620
621 authdb = keyfile_load(cfg, file);
622 }
623
624 if(authdb) {
625 if(cxMapPut(cfg->authdbs, cx_hash_key_bytes((
const unsigned char*)name.ptr, name.length), authdb)) {
626 return -
1;
627 }
628 }
629
630 return 0;
631 }
632
633 int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj) {
634 ListenerConfig lc;
635 ZERO(&lc,
sizeof(ListenerConfig));
636 lc.cfg = cfg;
637 lc.port =
8080;
638 lc.nacceptors =
1;
639
640 cxstring name = serverconfig_object_directive_value(obj, cx_str(
"Name"));
641 cxstring port = serverconfig_object_directive_value(obj, cx_str(
"Port"));
642 cxstring vs = serverconfig_object_directive_value(obj, cx_str(
"DefaultVS"));
643 cxstring thrp = serverconfig_object_directive_value(obj, cx_str(
"Threadpool"));
644 cxstring blck = serverconfig_object_directive_value(obj, cx_str(
"BlockingIO"));
645
646
647 int64_t port_value;
648 if(!util_strtoint(port.ptr, &port_value)) {
649 log_ereport(
LOG_MISCONFIG,
"Listener: Invalid argument for parameter ''Port'': ''%s''", port.ptr);
650 return 1;
651 }
652 if(port_value <
1 || port_value >
65535) {
653 log_ereport(
LOG_MISCONFIG,
"Listener: Port number out of range (1 .. 65535)");
654 return 1;
655 }
656
657 lc.name = cx_strdup(name);
658 lc.port = port_value;
659 lc.vs = cx_strdup(vs);
660 lc.threadpool = cx_strdup(thrp);
661
662 lc.blockingio = util_getboolean_s(blck,
WS_FALSE);
663
664 cxstring ssl = serverconfig_object_directive_value(obj, cx_str(
"SSL"));
665 if(util_getboolean_s(ssl,
WS_FALSE)) {
666 cxstring cert = serverconfig_object_directive_value(obj, cx_str(
"Cert"));
667 cxstring privkey = serverconfig_object_directive_value(obj, cx_str(
"Key"));
668 cxstring chain = serverconfig_object_directive_value(obj, cx_str(
"CertChain"));
669 cxstring disableprot = serverconfig_object_directive_value(obj, cx_str(
"SSLDisableProtocol"));
670
671 WSBool config_ok =
WS_TRUE;
672
673 if(!cert.ptr && !chain.ptr) {
674 log_ereport(
675 LOG_MISCONFIG,
676 "SSL Listener %s: Missing Cert or ChainCert directive",
677 lc.name.ptr);
678 config_ok =
WS_FALSE;
679 }
680 if(!privkey.ptr) {
681 log_ereport(
682 LOG_MISCONFIG,
683 "SSL Listener %s: Missing Key directive",
684 lc.name.ptr);
685 config_ok =
WS_FALSE;
686 }
687
688 if(config_ok) {
689 lc.certfile = cert;
690 lc.privkeyfile = privkey;
691 lc.chainfile = chain;
692 lc.disable_proto = disableprot;
693 lc.ssl =
WS_TRUE;
694 }
695 }
else {
696 lc.ssl =
WS_FALSE;
697 }
698
699
700
701 int ret =
0;
702 HttpListener *listener = http_listener_create(&lc);
703 if(listener) {
704 listener->default_vs.vs_name = cx_strdup_a(cfg->a, (cxstring){lc.vs.ptr, lc.vs.length}).ptr;
705 cxListAdd(cfg->listeners, listener);
706 }
else {
707 ret =
1;
708 }
709
710 free(lc.name.ptr);
711 free(lc.vs.ptr);
712 free(lc.threadpool.ptr);
713
714 return 0;
715 }
716
717 int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj) {
718 VirtualServer *vs = vs_new(cfg->pool);
719
720 vs->name = cx_strdup_a(cfg->a, serverconfig_object_directive_value(obj, cx_str(
"Name")));
721 vs->host = cx_strdup_a(cfg->a, serverconfig_object_directive_value(obj, cx_str(
"Host")));
722 vs->document_root = cx_strdup_a(cfg->a, serverconfig_object_directive_value(obj, cx_str(
"DocRoot")));
723
724 cxstring objfile = serverconfig_object_directive_value(obj, cx_str(
"ObjectFile"));
725 cxstring aclfile = serverconfig_object_directive_value(obj, cx_str(
"ACLFile"));
726
727
728 cxstring base = cx_str(
"config/");
729
730 cxmutstr file = cx_strcat_a(cfg->a,
2, base, objfile);
731
732 HTTPObjectConfig *httpobj = objconf_load(cfg, file);
733 if(!httpobj) {
734 return -
1;
735 }
736 vs->objectfile = file;
737 vs->objects = httpobj;
738
739
740
741 cxmutstr acl_filepath = cx_strcat(
2, base, aclfile);
742
743 ACLData *acldata = acl_conf_load(cfg, acl_filepath.ptr);
744 free(acl_filepath.ptr);
745 if(!acldata) {
746 return -
1;
747 }
748 vs->acls = acldata;
749
750
751
752
753 vs->log = cfg->default_log;
754
755 cxMapPut(cfg->host_vs, cx_hash_key_bytes((
unsigned const char*)vs->host.ptr, vs->host.length), vs);
756
757 return 0;
758 }
759
760 int cfg_handle_dav(ServerConfiguration *cfg, ConfigNode *obj) {
761 CxAllocator *a = pool_allocator(cfg->pool);
762 CxList *backends = cxLinkedListCreate(a,
NULL,
CX_STORE_POINTERS);
763 int init_error;
764
765
766 char *uri =
NULL;
767 char *ppath =
NULL;
768 char *name =
NULL;
769 for(ConfigParam *arg=obj->args;arg;arg=arg->next) {
770 cxstring arg_name = (cxstring){ arg->name.ptr, arg->name.length };
771 if(arg->name.ptr ==
NULL) {
772
773 uri = arg->value.ptr;
774 }
else if(!cx_strcasecmp(arg_name, cx_str(
"uri"))) {
775 uri = arg->value.ptr;
776 }
else if(!cx_strcasecmp(arg_name, cx_str(
"ppath"))) {
777 ppath = arg->value.ptr;
778 }
else if(!cx_strcasecmp(arg_name, cx_str(
"name"))) {
779 name = arg->value.ptr;
780 }
781 }
782 if(!uri && !ppath && !name) {
783 return 1;
784 }
785
786
787 for(ConfigNode *node=obj->children_begin;node;node=node->next) {
788 cxstring node_name = cx_strn(node->name.ptr, node->name.length);
789 if(!cx_strcasecmp(node_name, cx_str(
"DavBackend"))) {
790 if(node->type ==
CONFIG_NODE_DIRECTIVE) {
791 if(
CFG_NUM_PARAMS(node->args) ==
1) {
792 cxListAdd(backends, node->args);
793 }
else {
794 log_ereport(
LOG_MISCONFIG,
"DavBackend must have only one value");
795 cxListDestroy(backends);
796 return 1;
797 }
798 }
else {
799 log_ereport(
LOG_MISCONFIG,
"DavBackend must be a directive");
800 cxListDestroy(backends);
801 return 1;
802 }
803 }
804 }
805
806 int ret =
0;
807 WebdavRepository *repository = pool_malloc(cfg->pool,
sizeof(WebdavRepository));
808 repository->vfs =
NULL;
809 repository->vfsInitData =
NULL;
810 repository->davBackends = cxLinkedListCreate(a,
NULL,
CX_STORE_POINTERS);
811
812
813 CxIterator i = cxListIterator(backends);
814 cx_foreach(ConfigParam *, backendArg, i) {
815
816
817 WebdavType *dav = webdav_get_type((cxstring){backendArg->value.ptr, backendArg->value.length});
818 if(!dav) {
819 log_ereport(
LOG_MISCONFIG,
"Unknown webdav backend type ''%s''", backendArg->value.ptr);
820 ret =
1;
821 break;
822 }
823
824
825
826 void *init_data = webdav_init_backend(cfg, cfg->pool, dav, obj, &init_error);
827 if(init_error) {
828 log_ereport(
LOG_FAILURE,
"Failed to initialize webdav backend %s", backendArg->value.ptr);
829 ret =
1;
830 break;
831 }
832
833 WebdavBackendInitData *davInit = pool_malloc(cfg->pool,
sizeof(WebdavBackendInitData));
834 if(!davInit) {
835 log_ereport(
LOG_FAILURE,
"Failed to initialize webdav backend %s: OOM", backendArg->value.ptr);
836 ret =
1;
837 break;
838 }
839 davInit->davType = dav;
840 davInit->davInitData = init_data;
841
842 cxListAdd(repository->davBackends, davInit);
843 }
844 cxListDestroy(backends);
845
846
847 cxstring vfs_class = serverconfig_object_directive_value(obj, cx_str(
"VFS"));
848 if(vfs_class.length >
0) {
849 VfsType *vfs = vfs_get_type((cxstring){vfs_class.ptr, vfs_class.length});
850 if(vfs) {
851 repository->vfs = vfs;
852 repository->vfsInitData = vfs_init_backend(cfg, cfg->pool, vfs, obj, &init_error);
853 if(!ret) {
854 ret = init_error;
855 }
856 }
else {
857 log_ereport(
LOG_FAILURE,
"Unknown vfs type ''%s''", vfs_class.ptr);
858 ret =
1;
859 }
860 }
861
862 cxstring object = serverconfig_object_directive_value(obj, cx_str(
"Object"));
863 if(object.length >
0) {
864 repository->object = cx_strdup_a(a, object);
865 if(repository->object.length != object.length) {
866
867 log_ereport(
LOG_FAILURE,
"Cannot create webdav repository: OOM");
868 ret =
1;
869 }
870 }
871
872 if(!ret) {
873 if(name) {
874 cxMapPut(cfg->dav, cx_hash_key_str(name), repository);
875 }
else {
876 log_ereport(
LOG_FAILURE,
"TODO: location based dav repositories not implemented");
877 ret =
1;
878 }
879 }
880
881 return ret;
882 }
883
884
885 #define OBJ_CONF_MAX_CONDITION_DEPTH 500
886
887 static int set_client_condition(
pool_handle_t *pool, ConfigNode *node, Condition *condition) {
888 return 0;
889 }
890
891 static int set_if_condition(
pool_handle_t *pool, ConfigNode *node, Condition *condition) {
892
893
894
895
896
897
898 CxList *tokens = cxLinkedListCreate(pool_allocator(pool),
NULL,
sizeof(cxmutstr));
899 ConfigParam *arg = node->args;
900 while(arg) {
901 if(arg->name.length >
0) {
902
903
904 cxListAdd(tokens, &arg->name);
905 cxmutstr op = (cxmutstr){
"=",
1 };
906 cxListAdd(tokens, &op);
907 }
908 if(cxListAdd(tokens, &arg->value)) {
909 cxListDestroy(tokens);
910 return 1;
911 }
912 arg = arg->next;
913 }
914
915 int ret =
0;
916 condition->expression = condition_create(pool, tokens);
917 if(!condition->expression) {
918 ret =
1;
919 }
920
921
922 cxListDestroy(tokens);
923
924 return ret;
925 }
926
927
928 static Condition* convert_objconf_condition(
929 pool_handle_t *pool,
930 ConfigNode *node,
931 Condition *prev_condition,
932 Condition *parent_condition,
933 int *condition_index)
934 {
935 const char *condnames[] = {
"Client",
"If",
"ElseIf",
"Else" };
936 size_t typeindex;
937 if(serverconfig_validate_directive_name(node, condnames,
4, &typeindex)) {
938
939
940 return NULL;
941 }
942
943
944 if((typeindex ==
2 || typeindex ==
3) && prev_condition ==
NULL) {
945 return NULL;
946 }
947 Condition *condition = pool_malloc(pool,
sizeof(Condition));
948 ZERO(condition,
sizeof(Condition));
949
950 condition->index = *condition_index;
951 condition->parent = parent_condition;
952
953 if(typeindex ==
0) {
954
955 if(set_client_condition(pool, node, condition)) {
956 return NULL;
957 }
958 }
else {
959 condition->ifnot = prev_condition;
960
961
962 if(typeindex !=
4 && set_if_condition(pool, node, condition)) {
963 return NULL;
964 }
965 }
966
967 (*condition_index)++;
968 return condition;
969 }
970
971
972
973
974
975 static int convert_objconf_directives(
976 pool_handle_t *pool,
977 const char *file,
978 httpd_object *obj,
979 ConfigNode *node,
980 Condition *parent_condition,
981 int *condition_index)
982 {
983
984
985
986 Condition *prev_condition =
NULL;
987
988 for(;node;node=node->next) {
989 if(node->type ==
CONFIG_NODE_OBJECT) {
990 Condition *condition = convert_objconf_condition(pool, node, prev_condition, parent_condition, condition_index);
991 if(!condition) {
992 return 1;
993 }
994
995 if(convert_objconf_directives(pool, file, obj, node->children_begin, condition, condition_index)) {
996 return 1;
997 }
998
999
1000
1001
1002 if(!strcmp(node->name.ptr,
"If") || !strcmp(node->name.ptr,
"ElseIf")) {
1003 prev_condition = condition;
1004 }
else {
1005 prev_condition =
NULL;
1006 }
1007 }
else if(node->type ==
CONFIG_NODE_DIRECTIVE) {
1008 directive *d = pool_malloc(pool,
sizeof(directive));
1009 if(!d)
return -
1;
1010 d->param = pblock_create_pool(pool,
8);
1011
1012 d->cond = parent_condition;
1013
1014
1015 ConfigParam *param = node->args;
1016 while(param !=
NULL) {
1017 pblock_nvlinsert(
1018 param->name.ptr,
1019 param->name.length,
1020 param->value.ptr,
1021 param->value.length,
1022 d->param);
1023 param = param->next;
1024 }
1025
1026
1027 char *func_name = pblock_findval(
"fn", d->param);
1028 if(!func_name) {
1029 log_ereport(
LOG_MISCONFIG,
"%s: Missing fn parameter", file);
1030 return -
1;
1031 }
1032 d->func = get_function(func_name);
1033 if(!d->func) {
1034 log_ereport(
LOG_MISCONFIG,
"func %s not found", func_name);
1035 return -
1;
1036 }
1037
1038
1039 int dir_type = cfg_get_directive_type_num(cx_strcast(node->name));
1040 if(dir_type <
0) {
1041 log_ereport(
LOG_MISCONFIG,
"unknown directive type %s", node->name);
1042 }
1043 object_add_directive(obj, d, dir_type);
1044
1045 prev_condition =
NULL;
1046 }
1047 }
1048
1049 return 0;
1050 }
1051
1052 static int convert_objconf(ServerConfiguration *scfg, ObjectConfig2 *cfg, HTTPObjectConfig *conf, cxmutstr file) {
1053 pool_handle_t *pool = conf->pool;
1054
1055 int condition_index =
0;
1056
1057 int i =
0;
1058 for(ConfigNode *objnode=cfg->root->children_begin;objnode;objnode=objnode->next) {
1059 if(objnode->type !=
CONFIG_NODE_OBJECT) {
1060 if(objnode->type ==
CONFIG_NODE_DIRECTIVE) {
1061
1062 return 1;
1063 }
1064 continue;
1065 }
1066
1067 if(strcmp(objnode->name.ptr,
"Object")) {
1068
1069 return 1;
1070 }
1071
1072
1073 cxmutstr cfg_name = cfg_param_get(objnode->args, cx_str(
"name"));
1074 cxmutstr cfg_ppath = cfg_param_get(objnode->args, cx_str(
"ppath"));
1075
1076 char *name =
NULL;
1077 char *ppath =
NULL;
1078
1079 if(cfg_name.length >
0) {
1080 name = cx_strdup_pool(pool, cfg_name).ptr;
1081 if(!name)
return -
1;
1082 }
1083 if(cfg_ppath.length >
0) {
1084 ppath = cx_strdup_pool(pool, cfg_ppath).ptr;
1085 if(!ppath)
return -
1;
1086 }
1087
1088
1089 httpd_object *obj = object_new(pool, name);
1090 if(!obj)
return -
1;
1091 obj->path =
NULL;
1092
1093 conf->objects[i] = obj;
1094
1095
1096 if(convert_objconf_directives(pool, file.ptr, obj, objnode->children_begin,
NULL, &condition_index)) {
1097 return 1;
1098 }
1099
1100
1101 i++;
1102 }
1103
1104 return 0;
1105 }
1106
1107 HTTPObjectConfig* objconf_load(ServerConfiguration *scfg, cxmutstr file) {
1108 log_ereport(
LOG_VERBOSE,
"load_obj_conf");
1109
1110 int ret =
0;
1111
1112
1113 pool_handle_t *pool = scfg->pool;
1114 HTTPObjectConfig *conf = pool_calloc(pool,
sizeof(HTTPObjectConfig),
1);
1115 if(!conf) {
1116 return NULL;
1117 }
1118 conf->pool = pool;
1119
1120
1121 ObjectConfig2 *cfg = objectconf_load(file.ptr);
1122 if(!cfg) {
1123 return NULL;
1124 }
1125
1126
1127
1128
1129 conf->nobj = serverconfig_children_count(cfg->root,
CONFIG_NODE_OBJECT);
1130 conf->objects = pool_calloc(pool, conf->nobj,
sizeof(httpd_object*));
1131 if(conf->objects) {
1132 ret = convert_objconf(scfg, cfg, conf, file);
1133 }
else {
1134 ret = -
1;
1135 }
1136
1137 objectconf_free(cfg);
1138
1139 return !ret ? conf :
NULL;
1140 }
1141
1142 int mime_conf_load(ServerConfiguration *cfg, cxmutstr file) {
1143 MimeConfig *mimecfg = load_mime_config(file.ptr);
1144 if(!mimecfg) {
1145 return -
1;
1146 }
1147
1148 int ret =
0;
1149
1150
1151 MimeMap *mimemap = cxMalloc(cfg->a,
sizeof(MimeMap));
1152 CxMap *map = cxHashMapCreate(cfg->a,
CX_STORE_POINTERS, (mimecfg->ntypes *
3) /
2);
1153
1154 if(mimemap && map) {
1155 mimemap->map = map;
1156
1157
1158 for(MimeDirective *d=mimecfg->directives_begin;d;d=d->next) {
1159
1160 for(
int i=
0;i<d->nextensions;i++) {
1161 cxstring ext = d->extensions[i];
1162 cxmutstr value = cx_strdup(cx_strn(d->type.ptr, d->type.length));
1163 if(cxMapPut(map, cx_hash_key_bytes((
const unsigned char *)ext.ptr, ext.length), value.ptr)) {
1164 log_ereport(
LOG_CATASTROPHE,
"OOM");
1165 ret = -
1;
1166 break;
1167 }
1168 }
1169 if(ret) {
1170 break;
1171 }
1172 }
1173
1174 cfg->mimetypes = mimemap;
1175 }
else {
1176 log_ereport(
LOG_CATASTROPHE,
"OOM");
1177 ret = -
1;
1178 }
1179
1180 free_mime_config(mimecfg);
1181 return ret;
1182 }
1183
1184
1185
1186 ACLData* acl_conf_load(ServerConfiguration *cfg,
const char *file) {
1187 ACLFile *aclfile = load_acl_file(file);
1188 if(!aclfile) {
1189 log_ereport(
LOG_FAILURE,
"Cannot load acl file %s", file);
1190 return NULL;
1191 }
1192
1193
1194
1195 ACLData *acldata = acl_data_new(cfg->a);
1196 CxIterator iter = cxListIterator(aclfile->namedACLs);
1197 cx_foreach(ACLConfig *, ac, iter) {
1198 ACLList *acl = acl_config_convert(cfg, ac);
1199 log_ereport(
LOG_VERBOSE,
"add acl: %.*s", (
int)ac->id.length, ac->id.ptr);
1200 cxMapPut(acldata->namedACLs, cx_hash_key(ac->id.ptr, ac->id.length), acl);
1201 }
1202 free_acl_file(aclfile);
1203
1204 return acldata;
1205 }
1206
1207 ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) {
1208 CxAllocator *a = cfg->a;
1209
1210 WSAcl *acllist = cxMalloc(cfg->a,
sizeof(WSAcl));
1211 acllist->acl.check = (acl_check_f)wsacl_check;
1212 acllist->acl.authdb =
NULL;
1213 acllist->acl.authprompt =
NULL;
1214 acllist->acl.isextern =
0;
1215 acllist->ace =
NULL;
1216 acllist->ece =
NULL;
1217
1218 if(acl->type.ptr && !cx_strcmp(cx_strn(acl->type.ptr, acl->type.length), cx_str(
"fs"))) {
1219 acllist->acl.isextern =
1;
1220 }
1221
1222 size_t s =
CFG_ACE_LIST_SIZE(acl->entries);
1223 WSAce **tmp_aces = calloc(s,
sizeof(WSAce*));
1224 WSAce **tmp_eces = calloc(s,
sizeof(WSAce*));
1225 int ai =
0;
1226 int ei =
0;
1227
1228
1229 for(ACEConfig *acecfg=acl->entries;acecfg;acecfg=acecfg->next) {
1230
1231 WSAce *ace = cxMalloc(a,
sizeof(WSAce));
1232 ace->access_mask = acecfg->access_mask;
1233 ace->flags = acecfg->flags;
1234 ace->type = acecfg->type;
1235 ace->who = cx_strdup_a(a, cx_strcast(acecfg->who)).ptr;
1236
1237
1238 if(ace->type >=
ACL_TYPE_AUDIT) {
1239 tmp_eces[ei] = ace;
1240 ei++;
1241 }
else {
1242 tmp_aces[ai] = ace;
1243 ai++;
1244 }
1245 }
1246
1247
1248 if(ai >
0) {
1249 acllist->ace = cxCalloc(a, ai,
sizeof(WSAce*));
1250 }
1251 if(ei >
0) {
1252 acllist->ece = cxCalloc(a, ei,
sizeof(WSAce*));
1253 }
1254 memcpy(acllist->ace, tmp_aces, ai*
sizeof(WSAce*));
1255 memcpy(acllist->ece, tmp_eces, ei*
sizeof(WSAce*));
1256 acllist->acenum = ai;
1257 acllist->ecenum = ei;
1258
1259 free(tmp_aces);
1260 free(tmp_eces);
1261
1262
1263 if(acl->authparam) {
1264 cxmutstr authdb_str = cfg_param_get(acl->authparam, cx_str(
"authdb"));
1265 cxmutstr prompt_str = cfg_param_get(acl->authparam, cx_str(
"prompt"));
1266
1267 if(authdb_str.ptr) {
1268 AuthDB *authdb = cxMapGet(cfg->authdbs, cx_hash_key(authdb_str.ptr, authdb_str.length));
1269 acllist->acl.authdb = authdb;
1270 if(authdb && prompt_str.ptr) {
1271 acllist->acl.authprompt = cx_strdup_a(a, cx_strcast(prompt_str)).ptr;
1272 }
1273 }
1274 }
1275
1276 return &acllist->acl;
1277 }
1278
1279 AuthDB* keyfile_load(ServerConfiguration *cfg, cxstring file) {
1280 Keyfile *keyfile = keyfile_new(cfg->a);
1281 if(!keyfile) {
1282 return NULL;
1283 }
1284
1285 KeyfileConfig *conf = load_keyfile_config(file.ptr);
1286 if(!conf) {
1287 return NULL;
1288 }
1289
1290 AuthDB *ret = &keyfile->authdb;
1291
1292 for(KeyfileEntry *user=conf->users_begin;user;user=user->next) {
1293 if(keyfile_add_user(
1294 keyfile,
1295 user->name,
1296 user->hashtype,
1297 user->hashdata,
1298 user->groups,
1299 user->numgroups))
1300 {
1301 ret =
NULL;
1302 break;
1303 }
1304 }
1305
1306 free_keyfile_config(conf);
1307
1308 return ret;
1309 }
1310
1311 pblock* config_obj2pblock(
pool_handle_t *pool, ConfigNode *obj) {
1312 pblock *pb = pblock_create_pool(pool,
8);
1313 for(ConfigNode *d=obj->children_begin;d;d=d->next) {
1314 if(d->type ==
CONFIG_NODE_DIRECTIVE && d->name.length >
0 &&
CFG_NUM_PARAMS(d->args) ==
1) {
1315 ConfigParam *arg = d->args;
1316 pblock_nvlinsert(d->name.ptr, d->name.length, arg->value.ptr, arg->value.length, pb);
1317 }
1318 }
1319 return pb;
1320 }
1321