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 "config.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <cx/hash_map.h>
36 #include <errno.h>
37 #include <libxml/tree.h>
38 #include "utils.h"
39
40 #define xstreq(a,b) xmlStrEqual(
BAD_CAST a,
BAD_CAST b)
41 #define xstrEQ(a,b) !xmlStrcasecmp(
BAD_CAST a,
BAD_CAST b)
42
43 #define print_error(lineno, ...) \
44 do {\
45 fprintf(stderr,
"Error (config.xml line %u): ", lineno); \
46 fprintf(stderr,
__VA_ARGS__); \
47 fprintf(stderr,
"Abort.\n"); \
48 }
while(
0);
49 #define print_warning(lineno, ...) \
50 do {\
51 fprintf(stderr,
"Warning (config.xml line %u): ", lineno); \
52 fprintf(stderr,
__VA_ARGS__); \
53 }
while(
0);
54
55 #ifdef _WIN32
56 #define ENV_HOME getenv(
"USERPROFILE")
57 #else
58 #define ENV_HOME getenv(
"HOME")
59 #endif
60
61
62 static int load_repository(
63 DavConfig *config,
64 DavCfgRepository **list_begin,
65 DavCfgRepository **list_end,
66 xmlNode *reponode);
67 static int load_key(
68 DavConfig *config,
69 DavCfgKey **list_begin,
70 DavCfgKey **list_end,
71 xmlNode *keynode);
72 static int load_proxy(
73 DavConfig *config, DavCfgProxy *proxy, xmlNode *proxynode,
int type);
74 static int load_namespace(
75 DavConfig *config,
76 DavCfgNamespace **list_begin,
77 DavCfgNamespace **list_end,
78 xmlNode *node);
79 static int load_secretstore(DavConfig *config, xmlNode *node);
80
81
82 int dav_cfg_string_set_node_value(DavConfig *config, CfgString *str, xmlNode *node) {
83 str->node = node;
84 char *value = util_xml_get_text(node);
85 if(value) {
86 str->value = cx_strdup_a(config->mp->allocator, cx_str(value));
87 return 0;
88 }
else {
89 str->value = (cxmutstr){
NULL,
0};
90 return 1;
91 }
92 }
93
94 void dav_cfg_bool_set_node_value(DavConfig *config, CfgBool *cbool, xmlNode *node) {
95 cbool->node = node;
96 char *value = util_xml_get_text(node);
97 cbool->value = util_getboolean(value);
98 }
99
100 static void set_xml_content(xmlNode *node,
const char *content) {
101 xmlNode *child = node->children;
102 while(child) {
103 xmlNode *next = child->next;
104 xmlUnlinkNode(child);
105 xmlFreeNode(child);
106 child = next;
107 }
108
109 if(content) {
110 xmlChar *encoded = xmlEncodeSpecialChars(node->doc, (
const xmlChar*)content);
111 if(encoded) {
112 xmlNodeSetContent(node, encoded);
113 xmlFree(encoded);
114 }
115 }
116 }
117
118 void dav_cfg_string_set_value(DavConfig *config, CfgString *str, xmlNode *parent, cxstring new_value,
const char *nodename) {
119 if(str->value.ptr) {
120 cxFree(config->mp->allocator, str->value.ptr);
121 }
122 if(new_value.ptr) {
123 str->value = cx_strdup_a(config->mp->allocator, new_value);
124 }
else {
125 str->value = cx_mutstrn(
NULL,
0);
126 }
127
128 if(!str->node) {
129 str->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
130 xmlAddChild(parent, str->node);
131 }
132 set_xml_content(str->node, new_value.ptr);
133 }
134
135 void dav_cfg_bool_set_value(DavConfig *config, CfgBool *cbool, xmlNode *parent, DavBool new_value,
const char *nodename) {
136 const char *content = new_value ?
"true" :
"false";
137 cbool->value = new_value;
138 if(!cbool->node) {
139 cbool->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
140 xmlAddChild(parent, cbool->node);
141 }
142 set_xml_content(cbool->node, content);
143 }
144
145 void dav_cfg_int_set_value(DavConfig *config, CfgInt *cint, xmlNode *parent,
int64_t new_value,
const char *nodename) {
146 char content[
32];
147 snprintf(content,
32,
"%" PRId64, new_value);
148 cint->value = new_value;
149 if(!cint->node) {
150 cint->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
151 xmlAddChild(parent, cint->node);
152 }
153 set_xml_content(cint->node, content);
154 }
155
156 void dav_cfg_uint_set_value(DavConfig *config, CfgUInt *cint, xmlNode *parent,
uint64_t new_value,
const char *nodename) {
157 char content[
32];
158 snprintf(content,
32,
"%" PRIu64, new_value);
159 cint->value = new_value;
160 if(!cint->node) {
161 cint->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
162 xmlAddChild(parent, cint->node);
163 }
164 set_xml_content(cint->node, content);
165 }
166
167 void dav_cfg_string_remove(CfgString *str) {
168 if(str->node) {
169 xmlUnlinkNode(str->node);
170 xmlFreeNode(str->node);
171 str->node =
NULL;
172 }
173 }
174
175 void dav_cfg_bool_remove(CfgBool *cbool) {
176 if(cbool->node) {
177 xmlUnlinkNode(cbool->node);
178 xmlFreeNode(cbool->node);
179 cbool->node =
NULL;
180 }
181 }
182
183 void dav_cfg_int_remove(CfgInt *cint) {
184 if(cint->node) {
185 xmlUnlinkNode(cint->node);
186 xmlFreeNode(cint->node);
187 cint->node =
NULL;
188 }
189 }
190
191 void dav_cfg_uint_remove(CfgUInt *cint) {
192 if(cint->node) {
193 xmlUnlinkNode(cint->node);
194 xmlFreeNode(cint->node);
195 cint->node =
NULL;
196 }
197 }
198
199
200 DavConfig* dav_config_new(xmlDoc *doc) {
201 CxMempool *cfg_mp = cxMempoolCreate(
128,
NULL);
202 DavConfig *config = cxMalloc(cfg_mp->allocator,
sizeof(DavConfig));
203 memset(config,
0,
sizeof(DavConfig));
204 config->mp = cfg_mp;
205
206 if(!doc) {
207 doc = xmlNewDoc(
BAD_CAST "1.0");
208 xmlNode *root = xmlNewNode(
NULL,
BAD_CAST "configuration");
209 xmlDocSetRootElement(doc, root);
210 }
211 config->doc = doc;
212
213 return config;
214 }
215
216 DavConfig* dav_config_load(cxmutstr xmlfilecontent,
int *error) {
217 xmlDoc *doc = xmlReadMemory(xmlfilecontent.ptr, xmlfilecontent.length,
NULL,
NULL,
0);
218 if(!doc) {
219 if(error) {
220 *error =
DAV_CONFIG_ERROR_XML;
221 }
222 return NULL;
223 }
224
225 DavConfig *config = dav_config_new(doc);
226 CxMempool *cfg_mp = config->mp;
227 cxMempoolRegister(cfg_mp, doc, (cx_destructor_func)xmlFreeDoc);
228
229 DavCfgRepository *repos_begin =
NULL;
230 DavCfgRepository *repos_end =
NULL;
231 DavCfgKey *keys_begin =
NULL;
232 DavCfgKey *keys_end =
NULL;
233 DavCfgNamespace *namespaces_begin =
NULL;
234 DavCfgNamespace *namespaces_end =
NULL;
235
236 xmlNode *xml_root = xmlDocGetRootElement(doc);
237 xmlNode *node = xml_root->children;
238 int ret =
0;
239 while(node && !ret) {
240 if(node->type ==
XML_ELEMENT_NODE) {
241 if(xstreq(node->name,
"repository")) {
242 ret = load_repository(config, &repos_begin, &repos_end, node);
243 }
else if(xstreq(node->name,
"key")) {
244 ret = load_key(config, &keys_begin, &keys_end, node);
245 }
else if (xstreq(node->name,
"http-proxy")) {
246 config->http_proxy = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgProxy));
247 ret = load_proxy(config, config->http_proxy, node,
DAV_HTTP_PROXY);
248 }
else if (xstreq(node->name,
"https-proxy")) {
249 config->https_proxy = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgProxy));
250 ret = load_proxy(config, config->https_proxy, node,
DAV_HTTPS_PROXY);
251 }
else if (xstreq(node->name,
"namespace")) {
252 ret = load_namespace(config, &namespaces_begin, &namespaces_end, node);
253 }
else if (xstreq(node->name,
"secretstore")) {
254 ret = load_secretstore(config, node);
255 }
else {
256 fprintf(stderr,
"Unknown config element: %s\n", node->name);
257 ret =
1;
258 }
259 }
260 node = node->next;
261 }
262
263 config->repositories = repos_begin;
264 config->keys = keys_begin;
265 config->namespaces = namespaces_begin;
266
267 if(ret !=
0 && error) {
268 *error = ret;
269 cxMempoolDestroy(cfg_mp);
270 }
271
272 return config;
273 }
274
275 void dav_config_free(DavConfig *config) {
276 cxMempoolDestroy(config->mp);
277 }
278
279 CxBuffer* dav_config2buf(DavConfig *config) {
280 xmlChar* xmlText =
NULL;
281 int textLen =
0;
282 xmlDocDumpFormatMemory(config->doc, &xmlText, &textLen,
1);
283
284 if(!xmlText) {
285 return NULL;
286 }
287
288 CxBuffer *buf = cxBufferCreate(
NULL, textLen, cxDefaultAllocator,
CX_BUFFER_AUTO_EXTEND|
CX_BUFFER_FREE_CONTENTS);
289 cxBufferWrite(xmlText,
1, textLen, buf);
290 xmlFree(xmlText);
291 return buf;
292 }
293
294
295 static int repo_add_config(
296 DavConfig *config,
297 DavCfgRepository *repo,
298 xmlNode* node)
299 {
300 unsigned short lineno = node->line;
301 char *key = (
char*)node->name;
302 char *value = util_xml_get_text(node);
303
304
305 if(!value) {
306
307
308
309 print_error(lineno,
"missing value for config element: %s\n", key);
310 return 1;
311 }
312
313 if(xstreq(key,
"name")) {
314 dav_cfg_string_set_node_value(config, &repo->name, node);
315 }
else if(xstreq(key,
"url")) {
316 dav_cfg_string_set_node_value(config, &repo->url, node);
317 }
else if(xstreq(key,
"user")) {
318 dav_cfg_string_set_node_value(config, &repo->user, node);
319 }
else if(xstreq(key,
"password")) {
320 dav_cfg_string_set_node_value(config, &repo->password, node);
321 }
else if(xstreq(key,
"stored-user")) {
322 dav_cfg_string_set_node_value(config, &repo->stored_user, node);
323 }
else if(xstreq(key,
"default-key")) {
324 dav_cfg_string_set_node_value(config, &repo->default_key, node);
325 }
else if(xstreq(key,
"full-encryption")) {
326 dav_cfg_bool_set_node_value(config, &repo->full_encryption, node);
327 }
else if(xstreq(key,
"content-encryption")) {
328 dav_cfg_bool_set_node_value(config, &repo->content_encryption, node);
329 }
else if(xstreq(key,
"decrypt-content")) {
330 dav_cfg_bool_set_node_value(config, &repo->decrypt_content, node);
331 }
else if(xstreq(key,
"decrypt-name")) {
332 dav_cfg_bool_set_node_value(config, &repo->decrypt_name, node);
333 }
else if(xstreq(key,
"cert")) {
334 dav_cfg_string_set_node_value(config, &repo->cert, node);
335 }
else if(xstreq(key,
"verification")) {
336 dav_cfg_bool_set_node_value(config, &repo->verification, node);
337 }
else if(xstreq(key,
"ssl-version")) {
338 repo->ssl_version.node = node;
339 int ssl_version = dav_str2ssl_version((
const char*)value);
340 if(ssl_version == -
1) {
341 print_warning(lineno,
"unknown ssl version: %s\n", value);
342 repo->ssl_version.value =
CURL_SSLVERSION_DEFAULT;
343 }
else {
344 repo->ssl_version.value = ssl_version;
345 }
346 }
else if(xstreq(key,
"authmethods")) {
347 repo->authmethods.node = node;
348 repo->authmethods.value =
CURLAUTH_NONE;
349 const char *delims =
" \t\r\n";
350 char *meths = strdup(value);
351 char *meth = strtok(meths, delims);
352 while (meth) {
353 if(xstrEQ(meth,
"basic")) {
354 repo->authmethods.value |=
CURLAUTH_BASIC;
355 }
else if(xstrEQ(meth,
"digest")) {
356 repo->authmethods.value |=
CURLAUTH_DIGEST;
357 }
else if(xstrEQ(meth,
"negotiate")) {
358 repo->authmethods.value |=
CURLAUTH_GSSNEGOTIATE;
359 }
else if(xstrEQ(meth,
"ntlm")) {
360 repo->authmethods.value |=
CURLAUTH_NTLM;
361 }
else if(xstrEQ(meth,
"any")) {
362 repo->authmethods.value =
CURLAUTH_ANY;
363 }
else if(xstrEQ(meth,
"none")) {
364
365 }
else {
366 print_warning(lineno,
367 "unknown authentication method: %s\n", meth);
368 }
369 meth = strtok(
NULL, delims);
370 }
371 free(meths);
372 }
else {
373 print_error(lineno,
"unkown repository config element: %s\n", key);
374 return 1;
375 }
376 return 0;
377 }
378
379 int dav_str2ssl_version(
const char *value) {
380 if(xstrEQ(value,
"TLSv1")) {
381 return CURL_SSLVERSION_TLSv1;
382 }
else if(xstrEQ(value,
"SSLv2")) {
383 return CURL_SSLVERSION_SSLv2;
384 }
else if(xstrEQ(value,
"SSLv3")) {
385 return CURL_SSLVERSION_SSLv3;
386 }
387 #if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7034
388 else if(xstrEQ(value,
"TLSv1.0")) {
389 return CURL_SSLVERSION_TLSv1_0;
390 }
else if(xstrEQ(value,
"TLSv1.1")) {
391 return CURL_SSLVERSION_TLSv1_1;
392 }
else if(xstrEQ(value,
"TLSv1.2")) {
393 return CURL_SSLVERSION_TLSv1_2;
394 }
395 #endif
396 #if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7052
397 else if(xstrEQ(value,
"TLSv1.3")) {
398 return CURL_SSLVERSION_TLSv1_3;
399 }
400 #endif
401 return -
1;
402 }
403
404 static int load_repository(
405 DavConfig *config,
406 DavCfgRepository **list_begin,
407 DavCfgRepository **list_end,
408 xmlNode *reponode)
409 {
410 DavCfgRepository *repo = dav_repository_new(config);
411 repo->node = reponode;
412
413
414 xmlNode *node = reponode->children;
415 int ret =
0;
416 while(node && !ret) {
417 if(node->type ==
XML_ELEMENT_NODE) {
418 ret = repo_add_config(config, repo, node);
419 }
420 node = node->next;
421 }
422
423
424 if(ret) {
425 return 1;
426 }
else {
427 cx_linked_list_add(
428 (
void**)list_begin,
429 (
void**)list_end,
430 offsetof(DavCfgRepository, prev),
431 offsetof(DavCfgRepository, next),
432 repo);
433 }
434
435 return 0;
436 }
437
438 static xmlNode* addXmlNode(xmlNode *node,
const char *name, cxmutstr content) {
439 xmlNode *text1 = xmlNewDocText(node->doc,
BAD_CAST "\t\t");
440 xmlAddChild(node, text1);
441
442 cxmutstr ctn = cx_strdup(cx_strcast(content));
443 xmlNode *newNode = xmlNewChild(node,
NULL,
BAD_CAST name,
BAD_CAST ctn.ptr);
444 free(ctn.ptr);
445
446 xmlNode *text2 = xmlNewDocText(node->doc,
BAD_CAST "\n");
447 xmlAddChild(node, text2);
448
449 return newNode;
450 }
451
452 void dav_config_add_repository(DavConfig *config, DavCfgRepository *repo) {
453 if(repo->node) {
454 fprintf(stderr,
"Error: dav_config_add_repository: node already exists\n");
455 return;
456 }
457
458 xmlNode *repoNode = xmlNewNode(
NULL,
BAD_CAST "repository");
459 xmlNode *rtext1 = xmlNewDocText(config->doc,
BAD_CAST "\n");
460 xmlAddChild(repoNode, rtext1);
461 repo->node = repoNode;
462 if(repo->name.value.ptr) {
463 repo->name.node = addXmlNode(repoNode,
"name", repo->name.value);
464 }
465 if(repo->url.value.ptr) {
466 repo->url.node = addXmlNode(repoNode,
"url", repo->url.value);
467 }
468 if(repo->user.value.ptr) {
469 repo->user.node = addXmlNode(repoNode,
"user", repo->user.value);
470 }
471 if(repo->password.value.ptr) {
472 repo->password.node = addXmlNode(repoNode,
"password", repo->password.value);
473 }
474
475 if(repo->stored_user.value.ptr) {
476 repo->stored_user.node = addXmlNode(repoNode,
"stored-user", repo->stored_user.value);
477 }
478 if(repo->default_key.value.ptr) {
479 repo->default_key.node = addXmlNode(repoNode,
"default-key", repo->default_key.value);
480 }
481 if(repo->cert.value.ptr) {
482 repo->cert.node = addXmlNode(repoNode,
"cert", repo->cert.value);
483 }
484
485
486
487
488 xmlNode *rtext2 = xmlNewDocText(config->doc,
BAD_CAST "\t");
489 xmlAddChild(repoNode, rtext2);
490
491
492 DavCfgRepository **list_begin = &config->repositories;
493 cx_linked_list_add(
494 (
void**)list_begin,
495 NULL,
496 offsetof(DavCfgRepository, prev),
497 offsetof(DavCfgRepository, next),
498 repo);
499
500
501 xmlNode *xml_root = xmlDocGetRootElement(config->doc);
502
503 xmlNode *text1 = xmlNewDocText(config->doc,
BAD_CAST "\n\t");
504 xmlAddChild(xml_root, text1);
505
506 xmlAddChild(xml_root, repoNode);
507
508 xmlNode *text2 = xmlNewDocText(config->doc,
BAD_CAST "\n");
509 xmlAddChild(xml_root, text2);
510 }
511
512 DavCfgRepository* dav_repository_new(DavConfig *config) {
513 DavCfgRepository *repo = cxMalloc(config->mp->allocator,
sizeof(DavCfgRepository));
514 memset(repo,
0,
sizeof(DavCfgRepository));
515 repo->decrypt_name.value = false;
516 repo->decrypt_content.value = true;
517 repo->decrypt_properties.value = false;
518 repo->verification.value = true;
519 repo->ssl_version.value =
CURL_SSLVERSION_DEFAULT;
520 repo->authmethods.value =
CURLAUTH_BASIC;
521 return repo;
522 }
523
524 void dav_repository_free(DavConfig *config, DavCfgRepository *repo) {
525
526 }
527
528 void dav_repository_remove_and_free(DavConfig *config, DavCfgRepository *repo) {
529 if(repo->prev) {
530 repo->prev->next = repo->next;
531 }
532 if(repo->next) {
533 repo->next->prev = repo->prev;
534 }
535
536 if(repo->node) {
537
538
539 xmlUnlinkNode(repo->node);
540 xmlFreeNode(repo->node);
541 }
542 }
543
544 int dav_repository_get_flags(DavCfgRepository *repo) {
545 int flags =
0;
546
547 DavBool encrypt_content =
FALSE;
548 DavBool encrypt_name =
FALSE;
549 DavBool encrypt_properties =
FALSE;
550 DavBool decrypt_content =
FALSE;
551 DavBool decrypt_name =
FALSE;
552 DavBool decrypt_properties =
FALSE;
553 if(repo->full_encryption.value) {
554 encrypt_content =
TRUE;
555 encrypt_name =
TRUE;
556 encrypt_properties =
TRUE;
557 decrypt_content =
TRUE;
558 decrypt_name =
TRUE;
559 decrypt_properties =
TRUE;
560 }
else if(repo->content_encryption.value) {
561 encrypt_content =
TRUE;
562 decrypt_content =
TRUE;
563 }
564
565 if(decrypt_content) {
566 flags |=
DAV_SESSION_DECRYPT_CONTENT;
567 }
568 if(decrypt_name) {
569 flags |=
DAV_SESSION_DECRYPT_NAME;
570 }
571 if(decrypt_properties) {
572 flags |=
DAV_SESSION_DECRYPT_PROPERTIES;
573 }
574 if(encrypt_content) {
575 flags |=
DAV_SESSION_ENCRYPT_CONTENT;
576 }
577 if(encrypt_name) {
578 flags |=
DAV_SESSION_ENCRYPT_NAME;
579 }
580 if(encrypt_properties) {
581 flags |=
DAV_SESSION_ENCRYPT_PROPERTIES;
582 }
583 return flags;
584 }
585
586 void dav_repository_set_url(DavConfig *config, DavCfgRepository *repo, cxstring newurl) {
587 if(repo->url.value.ptr) {
588 cxFree(config->mp->allocator, repo->url.value.ptr);
589 }
590 repo->url.value = cx_strdup_a(config->mp->allocator, newurl);
591 }
592
593 void dav_repository_set_auth(DavConfig *config, DavCfgRepository *repo, cxstring user, cxstring password) {
594 const CxAllocator *a = config->mp->allocator;
595 if(user.length >
0) {
596 repo->user.value = cx_strdup_a(a, user);
597 }
598 if(password.length >
0) {
599 char *pwenc = util_base64encode(password.ptr, password.length);
600 repo->password.value = cx_strdup_a(a, cx_str(pwenc));
601 free(pwenc);
602 }
603 }
604
605 cxmutstr dav_repository_get_decodedpassword(DavCfgRepository *repo) {
606 cxmutstr pw = {
NULL,
0 };
607 if(repo->password.value.ptr) {
608 pw = cx_mutstr(util_base64decode(repo->password.value.ptr));
609 }
610 return pw;
611 }
612
613
614 void dav_config_add_key(DavConfig *config, DavCfgKey *key) {
615 cx_linked_list_add(
616 (
void**)&config->keys,
617 NULL,
618 offsetof(DavCfgKey, prev),
619 offsetof(DavCfgKey, next),
620 key);
621
622 if(key->node) {
623 fprintf(stderr,
"Error: dav_config_add_key: node already exists\n");
624 return;
625 }
626
627 xmlNode *keyNode = xmlNewNode(
NULL,
BAD_CAST "key");
628 xmlNode *rtext1 = xmlNewDocText(config->doc,
BAD_CAST "\n");
629 xmlAddChild(keyNode, rtext1);
630 key->node = keyNode;
631
632 if(key->name.value.ptr) {
633 key->name.node = addXmlNode(keyNode,
"name", key->name.value);
634 }
635 const char *type = dav_config_keytype_str(key->type);
636 if(type) {
637 key->type_node = addXmlNode(keyNode,
"type", cx_mutstr((
char*)type));
638 }
639 if(key->file.value.ptr) {
640 key->file.node = addXmlNode(keyNode,
"file", key->file.value);
641 }
642
643
644 xmlNode *rtext2 = xmlNewDocText(config->doc,
BAD_CAST "\t");
645 xmlAddChild(keyNode, rtext2);
646
647
648 xmlNode *xml_root = xmlDocGetRootElement(config->doc);
649
650 xmlNode *text1 = xmlNewDocText(config->doc,
BAD_CAST "\n\t");
651 xmlAddChild(xml_root, text1);
652
653 xmlAddChild(xml_root, keyNode);
654
655 xmlNode *text2 = xmlNewDocText(config->doc,
BAD_CAST "\n");
656 xmlAddChild(xml_root, text2);
657 }
658
659 DavCfgKey* dav_key_new(DavConfig *config) {
660 DavCfgKey *key = cxMalloc(config->mp->allocator,
sizeof(DavCfgKey));
661 memset(key,
0,
sizeof(DavCfgKey));
662 key->type =
DAV_KEY_TYPE_AES256;
663 return key;
664 }
665
666 void dav_key_remove_and_free(DavConfig *config, DavCfgKey *key) {
667 cx_linked_list_remove(
668 (
void**)&config->keys,
669 NULL,
670 offsetof(DavCfgKey, prev),
671 offsetof(DavCfgKey, next),
672 key);
673 if(key->node) {
674
675
676 xmlUnlinkNode(key->node);
677 xmlFreeNode(key->node);
678 }
679 }
680
681
682 static int load_key(
683 DavConfig *config,
684 DavCfgKey **list_begin,
685 DavCfgKey **list_end,
686 xmlNode *keynode)
687 {
688 xmlNode *node = keynode->children;
689 DavCfgKey *key = cxMalloc(config->mp->allocator,
sizeof(DavCfgKey));
690 memset(key,
0,
sizeof(DavCfgKey));
691 key->type =
DAV_KEY_TYPE_AES256;
692 key->node = keynode;
693
694 int error =
0;
695 while(node) {
696 if(node->type ==
XML_ELEMENT_NODE) {
697 if(xstreq(node->name,
"name")) {
698 dav_cfg_string_set_node_value(config, &key->name, node);
699 }
else if(xstreq(node->name,
"file")) {
700 dav_cfg_string_set_node_value(config, &key->file, node);
701 }
else if(xstreq(node->name,
"type")) {
702 const char *value = util_xml_get_text(node);
703 key->type_node = node;
704 if(!strcmp(value,
"aes128")) {
705 key->type =
DAV_KEY_TYPE_AES128;
706 }
else if(!strcmp(value,
"aes256")) {
707 key->type =
DAV_KEY_TYPE_AES256;
708 }
else {
709 print_error(node->line,
"unknown key type %s\n", value);
710 error =
1;
711 }
712 }
else {
713 key->unknown_elements++;
714 }
715
716 }
717 node = node->next;
718 }
719
720 if(!key->name.value.ptr) {
721 error =
1;
722 }
723
724 if(!error) {
725 error =
0;
726 size_t expected_length =
0;
727 if(key->type ==
DAV_KEY_TYPE_AES128) {
728 expected_length =
16;
729 }
730 if(key->type ==
DAV_KEY_TYPE_AES256) {
731 expected_length =
32;
732 }
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748 }
749
750
751 if(error) {
752 return 1;
753 }
else {
754
755 cx_linked_list_add(
756 (
void**)list_begin,
757 (
void**)list_end,
758 offsetof(DavCfgKey, prev),
759 offsetof(DavCfgKey, next),
760 key);
761
762 return 0;
763 }
764 }
765
766 static int load_proxy(
767 DavConfig *config, DavCfgProxy *proxy, xmlNode *proxynode,
int type)
768 {
769 const char *stype;
770 if(type ==
DAV_HTTPS_PROXY) {
771 stype =
"https";
772 }
else if(type ==
DAV_HTTP_PROXY) {
773 stype =
"http";
774 }
else {
775 fprintf(stderr,
"unknown proxy type\n");
776 return 1;
777 }
778
779 if(!proxy) {
780
781 fprintf(stderr,
"no memory reserved for %s proxy.\n", stype);
782 return 1;
783 }
784
785 xmlNode *node = proxynode->children;
786 int ret =
0;
787 while(node && !ret) {
788 if(node->type ==
XML_ELEMENT_NODE) {
789 int reportmissingvalue =
0;
790 if(xstreq(node->name,
"url")) {
791 reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->url, node);
792 }
else if(xstreq(node->name,
"user")) {
793 reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->user, node);
794 }
else if(xstreq(node->name,
"password")) {
795 reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->password, node);
796 }
else if(xstreq(node->name,
"no")) {
797 reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->noproxy, node);
798 }
else {
799 proxy->unknown_elements++;
800 }
801
802 if (reportmissingvalue) {
803 print_error(node->line,
804 "missing value for proxy configuration element: %s\n",
805 node->name);
806 ret =
1;
807 break;
808 }
809 }
810 node = node->next;
811 }
812
813 if(!ret && !proxy->url.value.ptr) {
814 print_error(proxynode->line,
"missing url for %s proxy.\n", stype);
815 return 1;
816 }
817
818 return ret;
819 }
820
821 static char* get_attr_content(xmlNode *node) {
822
823 while(node) {
824 if(node->type ==
XML_TEXT_NODE) {
825 return (
char*)node->content;
826 }
827 node = node->next;
828 }
829 return NULL;
830 }
831
832 static int load_namespace(
833 DavConfig *config,
834 DavCfgNamespace **list_begin,
835 DavCfgNamespace **list_end,
836 xmlNode *node)
837 {
838 const char *prefix =
NULL;
839 const char *uri =
NULL;
840 xmlAttr *attr = node->properties;
841 while(attr) {
842 if(attr->type ==
XML_ATTRIBUTE_NODE) {
843 char *value = get_attr_content(attr->children);
844 if(!value) {
845 print_error(
846 node->line,
847 "missing value for attribute %s\n", (
char*)attr->name);
848 return 1;
849 }
850 if(xstreq(attr->name,
"prefix")) {
851 prefix = value;
852 }
else if(xstreq(attr->name,
"uri")) {
853 uri = value;
854 }
else {
855 print_error(
856 node->line,
857 "unexpected attribute %s\n", (
char*)attr->name);
858 return 1;
859 }
860 }
861 attr = attr->next;
862 }
863
864 if(!prefix) {
865 print_error(node->line,
"missing prefix attribute\n");
866 return 1;
867 }
868 if(!uri) {
869 print_error(node->line,
"missing uri attribute\n");
870 return 1;
871 }
872
873 DavCfgNamespace *ns = cxMalloc(config->mp->allocator,
sizeof(DavCfgNamespace));
874 memset(ns,
0,
sizeof(DavCfgNamespace));
875 ns->node = node;
876 ns->prefix = cx_strdup_a(config->mp->allocator, cx_str(prefix));
877 ns->uri = cx_strdup_a(config->mp->allocator, cx_str(uri));
878 cx_linked_list_add(
879 (
void**)list_begin,
880 (
void**)list_end,
881 offsetof(DavCfgNamespace, prev),
882 offsetof(DavCfgNamespace, next),
883 ns);
884
885 return 0;
886 }
887
888 static int load_secretstore(DavConfig *config, xmlNode *node) {
889
890
891 if(config->secretstore) {
892 return 1;
893 }
894
895 config->secretstore = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgSecretStore));
896
897 node = node->children;
898 int error =
0;
899 while(node) {
900 if(node->type ==
XML_ELEMENT_NODE) {
901 if(xstreq(node->name,
"unlock-command")) {
902 dav_cfg_string_set_node_value(config, &config->secretstore->unlock_cmd, node);
903 }
else if(xstreq(node->name,
"lock-command")) {
904 dav_cfg_string_set_node_value(config, &config->secretstore->lock_cmd, node);
905 }
906 }
907 node = node->next;
908 }
909
910 return error;
911 }
912
913
914
915
916
917 DavCfgRepository* dav_config_get_repository(DavConfig *config, cxstring name) {
918 if(!config) {
919 return NULL;
920 }
921 DavCfgRepository *repo = config->repositories;
922 while(repo) {
923 if(!cx_strcmp(cx_strcast(repo->name.value), name)) {
924 return repo;
925 }
926 repo = repo->next;
927 }
928 return NULL;
929 }
930
931 DavCfgRepository* dav_config_url2repo(DavConfig *config,
const char *url,
char **path) {
932 cxmutstr p;
933 DavCfgRepository *repo = dav_config_url2repo_s(config, cx_str(url), &p);
934 *path = p.ptr;
935 return repo;
936 }
937
938 DavCfgRepository* dav_config_url2repo_s(DavConfig *config, cxstring url, cxmutstr *path) {
939 path->ptr =
NULL;
940 path->length =
0;
941
942 int s;
943 if(cx_strprefix(url,
CX_STR(
"http://"))) {
944 s =
7;
945 }
else if(cx_strprefix(url,
CX_STR(
"https://"))) {
946 s =
8;
947 }
else {
948 s =
1;
949 }
950
951
952 cxstring r = cx_strsubs(url, s);
953 cxstring p = cx_strchr(r,
'/');
954 r = cx_strsubsl(url,
0, url.length-p.length);
955 if(p.length ==
0) {
956 p = cx_strn(
"/",
1);
957 }
958
959 DavCfgRepository *repo = dav_config_get_repository(config, r);
960 if(repo) {
961 *path = cx_strdup(p);
962 }
else {
963
964
965 repo = dav_repository_new(config);
966 repo->name.value = cx_strdup_a(config->mp->allocator,
CX_STR(
""));
967 if(url.ptr[url.length-
1] ==
'/') {
968 repo->url.value = cx_strdup_a(config->mp->allocator, url);
969 *path = cx_strdup(
CX_STR(
"/"));
970 }
else if (cx_strchr(url,
'/').length >
0) {
971
972
973 cxstring repo_url = util_url_base_s(url);
974 repo->url.value = cx_strdup_a(config->mp->allocator, repo_url);
975 *path = cx_strdup(util_url_path_s(url));
976 }
else {
977 repo->url.value = cx_strdup(url);
978 *path = cx_strdup(
CX_STR(
"/"));
979 }
980 }
981
982 return repo;
983 }
984
985 int dav_config_keytype(DavCfgKeyType type) {
986 switch(type) {
987 default:
break;
988 case DAV_KEY_TYPE_AES256:
return DAV_KEY_AES256;
989 case DAV_KEY_TYPE_AES128:
return DAV_KEY_AES128;
990 }
991 return 0;
992 }
993
994 const char* dav_config_keytype_str(DavCfgKeyType type) {
995 switch(type) {
996 default:
break;
997 case DAV_KEY_TYPE_AES256:
return "aes256";
998 case DAV_KEY_TYPE_AES128:
return "aes128";
999 }
1000 return NULL;
1001 }
1002
1003 int dav_config_register_keys(DavConfig *config, DavContext *ctx, dav_loadkeyfile_func loadkey) {
1004 for(DavCfgKey *key=config->keys;key;key=key->next) {
1005 char *file = cx_strdup_m(key->file.value).ptr;
1006 cxmutstr keycontent = loadkey(file);
1007 free(file);
1008
1009
1010
1011 if(!keycontent.ptr) {
1012 return 1;
1013 }
1014
1015 DavKey *davkey = calloc(
1,
sizeof(DavKey));
1016 davkey->name = cx_strdup_m(key->name.value).ptr;
1017 davkey->type = dav_config_keytype(key->type);
1018 davkey->data = keycontent.ptr;
1019 davkey->length = keycontent.length;
1020
1021 dav_context_add_key(ctx, davkey);
1022 }
1023 return 0;
1024 }
1025
1026 int dav_config_register_namespaces(DavConfig *config, DavContext *ctx) {
1027 DavCfgNamespace *ns = config->namespaces;
1028 while(ns) {
1029 dav_add_namespace(ctx, ns->prefix.ptr, ns->uri.ptr);
1030 ns = ns->next;
1031 }
1032 return 0;
1033 }
1034