OpenDNSSEC-signer 2.1.13
confparser.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 NLNet Labs. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
32#include "config.h"
33#include "compat.h"
34#include "parser/confparser.h"
36#include "log.h"
37#include "status.h"
38#include "wire/acl.h"
39
40#include <libxml/xpath.h>
41#include <libxml/relaxng.h>
42#include <libxml/xmlreader.h>
43#include <string.h>
44#include <stdlib.h>
45#include <sys/un.h>
46
47static const char* parser_str = "parser";
48
49
54ods_status
55parse_file_check(const char* cfgfile, const char* rngfile)
56{
57 xmlDocPtr doc = NULL;
58 xmlDocPtr rngdoc = NULL;
59 xmlRelaxNGParserCtxtPtr rngpctx = NULL;
60 xmlRelaxNGValidCtxtPtr rngctx = NULL;
61 xmlRelaxNGPtr schema = NULL;
62 int status = 0;
63
64 if (!cfgfile || !rngfile) {
65 return ODS_STATUS_ASSERT_ERR;
66 }
67 ods_log_debug("[%s] check cfgfile %s with rngfile %s", parser_str,
68 cfgfile, rngfile);
69 /* Load XML document */
70 doc = xmlParseFile(cfgfile);
71 if (doc == NULL) {
72 ods_log_error("[%s] unable to parse file: failed to load cfgfile %s",
73 parser_str, cfgfile);
74 return ODS_STATUS_XML_ERR;
75 }
76 /* Load rng document */
77 rngdoc = xmlParseFile(rngfile);
78 if (rngdoc == NULL) {
79 ods_log_error("[%s] unable to parse file: failed to load rngfile %s",
80 parser_str, rngfile);
81 xmlFreeDoc(doc);
82 return ODS_STATUS_XML_ERR;
83 }
84 /* Create an XML RelaxNGs parser context for the relax-ng document. */
85 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
86 if (rngpctx == NULL) {
87 ods_log_error("[%s] unable to parse file: "
88 "xmlRelaxNGNewDocParserCtxt() failed", parser_str);
89 xmlFreeDoc(rngdoc);
90 xmlFreeDoc(doc);
91 return ODS_STATUS_XML_ERR;
92 }
93 /* Parse a schema definition resource and
94 * build an internal XML schema structure.
95 */
96 schema = xmlRelaxNGParse(rngpctx);
97 if (schema == NULL) {
98 ods_log_error("[%s] unable to parse file: xmlRelaxNGParse() failed",
99 parser_str);
100 xmlRelaxNGFreeParserCtxt(rngpctx);
101 xmlFreeDoc(rngdoc);
102 xmlFreeDoc(doc);
103 return ODS_STATUS_PARSE_ERR;
104 }
105 /* Create an XML RelaxNGs validation context. */
106 rngctx = xmlRelaxNGNewValidCtxt(schema);
107 if (rngctx == NULL) {
108 ods_log_error("[%s] unable to parse file: xmlRelaxNGNewValidCtxt() "
109 "failed", parser_str);
110 xmlRelaxNGFree(schema);
111 xmlRelaxNGFreeParserCtxt(rngpctx);
112 xmlFreeDoc(rngdoc);
113 xmlFreeDoc(doc);
114 return ODS_STATUS_RNG_ERR;
115 }
116 /* Validate a document tree in memory. */
117 status = xmlRelaxNGValidateDoc(rngctx,doc);
118 if (status != 0) {
119 ods_log_error("[%s] unable to parse file: xmlRelaxNGValidateDoc() "
120 "failed", parser_str);
121 xmlRelaxNGFreeValidCtxt(rngctx);
122 xmlRelaxNGFree(schema);
123 xmlRelaxNGFreeParserCtxt(rngpctx);
124 xmlFreeDoc(rngdoc);
125 xmlFreeDoc(doc);
126 return ODS_STATUS_RNG_ERR;
127 }
128 xmlRelaxNGFreeValidCtxt(rngctx);
129 xmlRelaxNGFree(schema);
130 xmlRelaxNGFreeParserCtxt(rngpctx);
131 xmlFreeDoc(rngdoc);
132 xmlFreeDoc(doc);
133 return ODS_STATUS_OK;
134}
135
136/* TODO: look how the enforcer reads this now */
137
142hsm_repository_t*
143parse_conf_repositories(const char* cfgfile)
144{
145 xmlDocPtr doc = NULL;
146 xmlXPathContextPtr xpathCtx = NULL;
147 xmlXPathObjectPtr xpathObj = NULL;
148 xmlNode* curNode = NULL;
149 xmlChar* xexpr = NULL;
150
151 int i;
152 char* name;
153 char* module;
154 char* tokenlabel;
155 char* pin;
156 uint8_t use_pubkey;
157 uint8_t allowextract;
158 int require_backup;
159 hsm_repository_t* rlist = NULL;
160 hsm_repository_t* repo = NULL;
161
162 /* Load XML document */
163 doc = xmlParseFile(cfgfile);
164 if (doc == NULL) {
165 ods_log_error("[%s] could not parse <RepositoryList>: "
166 "xmlParseFile() failed", parser_str);
167 return NULL;
168 }
169 /* Create xpath evaluation context */
170 xpathCtx = xmlXPathNewContext(doc);
171 if(xpathCtx == NULL) {
172 xmlFreeDoc(doc);
173 ods_log_error("[%s] could not parse <RepositoryList>: "
174 "xmlXPathNewContext() failed", parser_str);
175 return NULL;
176 }
177 /* Evaluate xpath expression */
178 xexpr = (xmlChar*) "//Configuration/RepositoryList/Repository";
179 xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
180 if(xpathObj == NULL) {
181 xmlXPathFreeContext(xpathCtx);
182 xmlFreeDoc(doc);
183 ods_log_error("[%s] could not parse <RepositoryList>: "
184 "xmlXPathEvalExpression failed", parser_str);
185 return NULL;
186 }
187 /* Parse repositories */
188 if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
189 for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
190 repo = NULL;
191 name = NULL;
192 module = NULL;
193 tokenlabel = NULL;
194 pin = NULL;
195 use_pubkey = 1;
196 allowextract = 0;
197 require_backup = 0;
198
199 curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
200 name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i],
201 (const xmlChar *)"name");
202 while (curNode) {
203 if (xmlStrEqual(curNode->name, (const xmlChar *)"RequireBackup"))
204 require_backup = 1;
205 if (xmlStrEqual(curNode->name, (const xmlChar *)"Module"))
206 module = (char *) xmlNodeGetContent(curNode);
207 if (xmlStrEqual(curNode->name, (const xmlChar *)"TokenLabel"))
208 tokenlabel = (char *) xmlNodeGetContent(curNode);
209 if (xmlStrEqual(curNode->name, (const xmlChar *)"PIN"))
210 pin = (char *) xmlNodeGetContent(curNode);
211 if (xmlStrEqual(curNode->name, (const xmlChar *)"SkipPublicKey"))
212 use_pubkey = 0;
213 if (xmlStrEqual(curNode->name, (const xmlChar *)"AllowExtraction"))
214 allowextract = 1;
215
216 curNode = curNode->next;
217 }
218 if (name && module && tokenlabel) {
219 repo = hsm_repository_new(name, module, tokenlabel, pin,
220 use_pubkey, allowextract, require_backup);
221 }
222 if (!repo) {
223 ods_log_error("[%s] unable to add %s repository: "
224 "hsm_repository_new() failed", parser_str, name?name:"-");
225 } else {
226 repo->next = rlist;
227 rlist = repo;
228 ods_log_debug("[%s] added %s repository to repositorylist",
229 parser_str, name);
230 }
231 free((void*)name);
232 free((void*)module);
233 free((void*)tokenlabel);
234 free((void*)pin);
235 }
236 }
237
238 xmlXPathFreeObject(xpathObj);
239 xmlXPathFreeContext(xpathCtx);
240 if (doc) {
241 xmlFreeDoc(doc);
242 }
243 return rlist;
244}
245
246
252parse_conf_listener(const char* cfgfile)
253{
254 listener_type* listener = NULL;
255 interface_type* interface = NULL;
256 int i = 0;
257 char* address = NULL;
258 const char* port = NULL;
259 xmlDocPtr doc = NULL;
260 xmlXPathContextPtr xpathCtx = NULL;
261 xmlXPathObjectPtr xpathObj = NULL;
262 xmlNode* curNode = NULL;
263 xmlChar* xexpr = NULL;
264
265 ods_log_assert(cfgfile);
266
267 /* Load XML document */
268 doc = xmlParseFile(cfgfile);
269 if (doc == NULL) {
270 ods_log_error("[%s] could not parse <Listener>: "
271 "xmlParseFile() failed", parser_str);
272 return NULL;
273 }
274 /* Create xpath evaluation context */
275 xpathCtx = xmlXPathNewContext(doc);
276 if(xpathCtx == NULL) {
277 xmlFreeDoc(doc);
278 ods_log_error("[%s] could not parse <Listener>: "
279 "xmlXPathNewContext() failed", parser_str);
280 return NULL;
281 }
282 /* Evaluate xpath expression */
283 xexpr = (xmlChar*) "//Configuration/Signer/Listener/Interface";
284 xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
285 if(xpathObj == NULL) {
286 xmlXPathFreeContext(xpathCtx);
287 xmlFreeDoc(doc);
288 ods_log_error("[%s] could not parse <Listener>: "
289 "xmlXPathEvalExpression failed", parser_str);
290 return NULL;
291 }
292 /* Parse interfaces */
293 listener = listener_create();
294 ods_log_assert(listener);
295
296 /* If port is not set in Listener in the conf file, default value is used.
297 * default port: 15354
298 */
299 if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
300 for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
301 address = NULL;
302 port = strdup("15354");
303
304 curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
305 while (curNode) {
306 if (xmlStrEqual(curNode->name, (const xmlChar *)"Address")) {
307 address = (char *) xmlNodeGetContent(curNode);
308 } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Port")) {
309 free((char *)port);
310 port = (char *) xmlNodeGetContent(curNode);
311 }
312 curNode = curNode->next;
313 }
314 if (address) {
315 interface = listener_push(listener, address,
316 acl_parse_family(address), port);
317 } else {
318 interface = listener_push(listener, (char *)"", AF_INET, port);
319 if (interface) {
320 interface = listener_push(listener, (char *)"", AF_INET6, port);
321 }
322 }
323 if (!interface) {
324 ods_log_error("[%s] unable to add %s:%s interface: "
325 "listener_push() failed", parser_str, address?address:"",
326 port);
327 } else {
328 ods_log_debug("[%s] added %s:%s interface to listener",
329 parser_str, address?address:"", port);
330 }
331 free((void*)port);
332 free((void*)address);
333 }
334 }
335 else {
336 interface = listener_push(listener, (char *)"", AF_INET, "15354");
337 if (interface) {
338 interface = listener_push(listener, (char *)"", AF_INET6, "15354");
339 }
340 }
341 xmlXPathFreeObject(xpathObj);
342 xmlXPathFreeContext(xpathCtx);
343 if (doc) {
344 xmlFreeDoc(doc);
345 }
346 return listener;
347}
348
349
354const char*
355parse_conf_string(const char* cfgfile, const char* expr, int required)
356{
357 xmlDocPtr doc = NULL;
358 xmlXPathContextPtr xpathCtx = NULL;
359 xmlXPathObjectPtr xpathObj = NULL;
360 xmlChar *xexpr = NULL;
361 const char* string = NULL;
362
363 ods_log_assert(expr);
364 ods_log_assert(cfgfile);
365
366 /* Load XML document */
367 doc = xmlParseFile(cfgfile);
368 if (doc == NULL) {
369 ods_log_error("[%s] unable to parse file %s: xmlParseFile() failed",
370 parser_str, cfgfile);
371 return NULL;
372 }
373 /* Create xpath evaluation context */
374 xpathCtx = xmlXPathNewContext(doc);
375 if (xpathCtx == NULL) {
376 ods_log_error("[%s] unable to parse file %s: xmlXPathNewContext() "
377 "failed", parser_str, cfgfile);
378 xmlFreeDoc(doc);
379 return NULL;
380 }
381 /* Get string */
382 xexpr = (unsigned char*) expr;
383 xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
384 if (xpathObj == NULL || xpathObj->nodesetval == NULL ||
385 xpathObj->nodesetval->nodeNr <= 0) {
386 if (required) {
387 ods_log_error("[%s] unable to evaluate expression %s in cfgile %s",
388 parser_str, (char*) xexpr, cfgfile);
389 }
390 xmlXPathFreeContext(xpathCtx);
391 if (xpathObj) {
392 xmlXPathFreeObject(xpathObj);
393 }
394 xmlFreeDoc(doc);
395 return NULL;
396 }
397 if (xpathObj->nodesetval != NULL &&
398 xpathObj->nodesetval->nodeNr > 0) {
399 string = (const char*) xmlXPathCastToString(xpathObj);
400 xmlXPathFreeContext(xpathCtx);
401 xmlXPathFreeObject(xpathObj);
402 xmlFreeDoc(doc);
403 return string;
404 }
405 xmlXPathFreeContext(xpathCtx);
406 xmlXPathFreeObject(xpathObj);
407 xmlFreeDoc(doc);
408 return NULL;
409}
410
411/*
412 * TODO all parse routines parse the complete file. Yuk!
413 * TODO make a parse_conf_bool for testing existence of empty elements
414 * instead of abusing parse_conf_string
415 * */
416
417const char*
419{
420 int lwd = 0;
421 int lzl = 0;
422 int found = 0;
423 char* dup = NULL;
424 const char* str = parse_conf_string(
425 cfgfile,
426 "//Configuration/Enforcer/WorkingDirectory",
427 0);
428
429 if (str) {
430 found = 1;
431 } else {
432 str = OPENDNSSEC_ENFORCER_WORKINGDIR;
433 }
434 lwd = strlen(str);
435 lzl = strlen(OPENDNSSEC_ENFORCER_ZONELIST);
436 if (lwd>0 && strncmp(str + (lwd-1), "/", 1) != 0) {
437 CHECKALLOC(dup = malloc(sizeof(char)*(lwd+lzl+2)));
438 memcpy(dup, str, sizeof(char)*(lwd+1));
439 strlcat(dup, "/", sizeof(char)*(lwd+2));
440 strlcat(dup, OPENDNSSEC_ENFORCER_ZONELIST, sizeof(char)*(lwd+lzl+2));
441 lwd += (lzl+1);
442 } else {
443 CHECKALLOC(dup = malloc(sizeof(char)*(lwd+lzl+1)));
444 memcpy(dup, str, sizeof(char)*(lwd+1));
445 strlcat(dup, OPENDNSSEC_ENFORCER_ZONELIST, sizeof(char)*(lwd+lzl+1));
446 lwd += (lzl+1);
447 }
448 if (found) {
449 free((void*)str);
450 }
451 ods_log_assert(dup);
452 return (const char*) dup;
453}
454
455
456const char*
457parse_conf_log_filename(const char* cfgfile)
458{
459 const char* dup = NULL;
460 const char* str = parse_conf_string(cfgfile,
461 "//Configuration/Common/Logging/Syslog/Facility",
462 0);
463 if (!str) {
464 str = parse_conf_string(cfgfile,
465 "//Configuration/Common/Logging/File/Filename",
466 0);
467 }
468 if (str) {
469 dup = strdup(str);
470 free((void*)str);
471 }
472 return dup; /* NULL, Facility or Filename */
473}
474
475
476const char*
477parse_conf_pid_filename(const char* cfgfile)
478{
479 const char* dup = NULL;
480 const char* str = parse_conf_string(
481 cfgfile,
482 "//Configuration/Signer/PidFile",
483 0);
484
485 if (str) {
486 dup = strdup(str);
487 free((void*)str);
488 } else {
489 dup = strdup(ODS_SE_PIDFILE);
490 }
491 return dup;
492}
493
494
495const char*
496parse_conf_notify_command(const char* cfgfile)
497{
498 const char* dup = NULL;
499 const char* str = parse_conf_string(
500 cfgfile,
501 "//Configuration/Signer/NotifyCommand",
502 0);
503
504 if (str) {
505 dup = strdup(str);
506 free((void*)str);
507 }
508 return dup;
509}
510
511
512const char*
513parse_conf_clisock_filename(const char* cfgfile)
514{
515 char* dup = NULL;
516 const char* str = parse_conf_string(
517 cfgfile,
518 "//Configuration/Signer/SocketFile",
519 0);
520
521 if (str) {
522 dup = strdup(str);
523 free((void*)str);
524 } else {
525 dup = strdup(ODS_SE_SOCKFILE);
526 }
527 if (strlen(dup) >= sizeof(((struct sockaddr_un*)0)->sun_path)) {
528 dup[sizeof(((struct sockaddr_un*)0)->sun_path)-1] = '\0'; /* don't worry about just a few bytes 'lost' */
529 ods_log_warning("[%s] SocketFile path too long, truncated to %s", parser_str, dup);
530 }
531 return dup;
532}
533
534
535const char*
536parse_conf_working_dir(const char* cfgfile)
537{
538 const char* dup = NULL;
539 const char* str = parse_conf_string(
540 cfgfile,
541 "//Configuration/Signer/WorkingDirectory",
542 0);
543
544 if (str) {
545 dup = strdup(str);
546 free((void*)str);
547 } else {
548 dup = strdup(ODS_SE_WORKDIR);
549 }
550 ods_log_assert(dup);
551 return dup;
552}
553
554
555const char*
556parse_conf_username(const char* cfgfile)
557{
558 const char* dup = NULL;
559 const char* str = parse_conf_string(
560 cfgfile,
561 "//Configuration/Signer/Privileges/User",
562 0);
563
564 if (str) {
565 dup = strdup(str);
566 free((void*)str);
567 }
568 return dup;
569}
570
571
572const char*
573parse_conf_group(const char* cfgfile)
574{
575 const char* dup = NULL;
576 const char* str = parse_conf_string(
577 cfgfile,
578 "//Configuration/Signer/Privileges/Group",
579 0);
580
581 if (str) {
582 dup = strdup(str);
583 free((void*)str);
584 }
585 return dup;
586}
587
588
589const char*
590parse_conf_chroot(const char* cfgfile)
591{
592 const char* dup = NULL;
593 const char* str = parse_conf_string(
594 cfgfile,
595 "//Configuration/Signer/Privileges/Directory",
596 0);
597
598 if (str) {
599 dup = strdup(str);
600 free((void*)str);
601 }
602 return dup;
603}
604
605
610int
611parse_conf_use_syslog(const char* cfgfile)
612{
613 const char* str = parse_conf_string(cfgfile,
614 "//Configuration/Common/Logging/Syslog/Facility",
615 0);
616 if (str) {
617 free((void*)str);
618 return 1;
619 }
620 return 0;
621}
622
623int
624parse_conf_verbosity(const char* cfgfile)
625{
626 int verbosity = ODS_SE_VERBOSITY;
627 const char* str = parse_conf_string(cfgfile,
628 "//Configuration/Common/Logging/Verbosity",
629 0);
630 if (str) {
631 if (strlen(str) > 0) {
632 verbosity = atoi(str);
633 }
634 free((void*)str);
635 }
636 return verbosity;
637}
638
639
640int
641parse_conf_worker_threads(const char* cfgfile)
642{
643 int numwt = ODS_SE_WORKERTHREADS;
644 const char* str = parse_conf_string(cfgfile,
645 "//Configuration/Signer/WorkerThreads",
646 0);
647 if (str) {
648 if (strlen(str) > 0) {
649 numwt = atoi(str);
650 }
651 free((void*)str);
652 }
653 return numwt;
654}
655
656
657int
658parse_conf_signer_threads(const char* cfgfile)
659{
660 int numwt = ODS_SE_WORKERTHREADS;
661 const char* str = parse_conf_string(cfgfile,
662 "//Configuration/Signer/SignerThreads",
663 0);
664 if (str) {
665 if (strlen(str) > 0) {
666 numwt = atoi(str);
667 }
668 free((void*)str);
669 return numwt;
670 }
671 /* no SignerThreads value configured, look at WorkerThreads */
672 return parse_conf_worker_threads(cfgfile);
673}
int acl_parse_family(const char *a)
Definition acl.c:104
const char * parse_conf_clisock_filename(const char *cfgfile)
Definition confparser.c:513
const char * parse_conf_zonelist_filename(const char *cfgfile)
Definition confparser.c:418
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition confparser.c:143
const char * parse_conf_working_dir(const char *cfgfile)
Definition confparser.c:536
const char * parse_conf_log_filename(const char *cfgfile)
Definition confparser.c:457
int parse_conf_worker_threads(const char *cfgfile)
Definition confparser.c:641
const char * parse_conf_username(const char *cfgfile)
Definition confparser.c:556
const char * parse_conf_pid_filename(const char *cfgfile)
Definition confparser.c:477
int parse_conf_signer_threads(const char *cfgfile)
Definition confparser.c:658
int parse_conf_use_syslog(const char *cfgfile)
Definition confparser.c:611
const char * parse_conf_notify_command(const char *cfgfile)
Definition confparser.c:496
const char * parse_conf_chroot(const char *cfgfile)
Definition confparser.c:590
const char * parse_conf_group(const char *cfgfile)
Definition confparser.c:573
int parse_conf_verbosity(const char *cfgfile)
Definition confparser.c:624
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition confparser.c:55
const char * parse_conf_string(const char *cfgfile, const char *expr, int required)
Definition confparser.c:355
listener_type * parse_conf_listener(const char *cfgfile)
Definition confparser.c:252
interface_type * listener_push(listener_type *listener, char *address, int family, const char *port)
Definition listener.c:60
listener_type * listener_create()
Definition listener.c:45