OpenDNSSEC-signer  2.0.3
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"
35 #include "parser/zonelistparser.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 
47 static const char* parser_str = "parser";
48 
49 
54 ods_status
55 parse_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 
142 hsm_repository_t*
143 parse_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  int require_backup;
158  hsm_repository_t* rlist = NULL;
159  hsm_repository_t* repo = NULL;
160 
161  /* Load XML document */
162  doc = xmlParseFile(cfgfile);
163  if (doc == NULL) {
164  ods_log_error("[%s] could not parse <RepositoryList>: "
165  "xmlParseFile() failed", parser_str);
166  return NULL;
167  }
168  /* Create xpath evaluation context */
169  xpathCtx = xmlXPathNewContext(doc);
170  if(xpathCtx == NULL) {
171  xmlFreeDoc(doc);
172  ods_log_error("[%s] could not parse <RepositoryList>: "
173  "xmlXPathNewContext() failed", parser_str);
174  return NULL;
175  }
176  /* Evaluate xpath expression */
177  xexpr = (xmlChar*) "//Configuration/RepositoryList/Repository";
178  xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
179  if(xpathObj == NULL) {
180  xmlXPathFreeContext(xpathCtx);
181  xmlFreeDoc(doc);
182  ods_log_error("[%s] could not parse <RepositoryList>: "
183  "xmlXPathEvalExpression failed", parser_str);
184  return NULL;
185  }
186  /* Parse repositories */
187  if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
188  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
189  repo = NULL;
190  name = NULL;
191  module = NULL;
192  tokenlabel = NULL;
193  pin = NULL;
194  use_pubkey = 1;
195  require_backup = 0;
196 
197  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
198  name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i],
199  (const xmlChar *)"name");
200  while (curNode) {
201  if (xmlStrEqual(curNode->name, (const xmlChar *)"RequireBackup"))
202  require_backup = 1;
203  if (xmlStrEqual(curNode->name, (const xmlChar *)"Module"))
204  module = (char *) xmlNodeGetContent(curNode);
205  if (xmlStrEqual(curNode->name, (const xmlChar *)"TokenLabel"))
206  tokenlabel = (char *) xmlNodeGetContent(curNode);
207  if (xmlStrEqual(curNode->name, (const xmlChar *)"PIN"))
208  pin = (char *) xmlNodeGetContent(curNode);
209  if (xmlStrEqual(curNode->name, (const xmlChar *)"SkipPublicKey"))
210  use_pubkey = 0;
211 
212  curNode = curNode->next;
213  }
214  if (name && module && tokenlabel) {
215  repo = hsm_repository_new(name, module, tokenlabel, pin,
216  use_pubkey, require_backup);
217  }
218  if (!repo) {
219  ods_log_error("[%s] unable to add %s repository: "
220  "hsm_repository_new() failed", parser_str, name?name:"-");
221  } else {
222  repo->next = rlist;
223  rlist = repo;
224  ods_log_debug("[%s] added %s repository to repositorylist",
225  parser_str, name);
226  }
227  free((void*)name);
228  free((void*)module);
229  free((void*)tokenlabel);
230  free((void*)pin);
231  }
232  }
233 
234  xmlXPathFreeObject(xpathObj);
235  xmlXPathFreeContext(xpathCtx);
236  if (doc) {
237  xmlFreeDoc(doc);
238  }
239  return rlist;
240 }
241 
242 
248 parse_conf_listener(const char* cfgfile)
249 {
250  listener_type* listener = NULL;
251  interface_type* interface = NULL;
252  int i = 0;
253  char* address = NULL;
254  char* port = NULL;
255  xmlDocPtr doc = NULL;
256  xmlXPathContextPtr xpathCtx = NULL;
257  xmlXPathObjectPtr xpathObj = NULL;
258  xmlNode* curNode = NULL;
259  xmlChar* xexpr = NULL;
260 
261  ods_log_assert(cfgfile);
262 
263  /* Load XML document */
264  doc = xmlParseFile(cfgfile);
265  if (doc == NULL) {
266  ods_log_error("[%s] could not parse <Listener>: "
267  "xmlParseFile() failed", parser_str);
268  return NULL;
269  }
270  /* Create xpath evaluation context */
271  xpathCtx = xmlXPathNewContext(doc);
272  if(xpathCtx == NULL) {
273  xmlFreeDoc(doc);
274  ods_log_error("[%s] could not parse <Listener>: "
275  "xmlXPathNewContext() failed", parser_str);
276  return NULL;
277  }
278  /* Evaluate xpath expression */
279  xexpr = (xmlChar*) "//Configuration/Signer/Listener/Interface";
280  xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
281  if(xpathObj == NULL) {
282  xmlXPathFreeContext(xpathCtx);
283  xmlFreeDoc(doc);
284  ods_log_error("[%s] could not parse <Listener>: "
285  "xmlXPathEvalExpression failed", parser_str);
286  return NULL;
287  }
288  /* Parse interfaces */
289  listener = listener_create();
290  ods_log_assert(listener);
291  if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
292  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
293  address = NULL;
294  port = NULL;
295 
296  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
297  while (curNode) {
298  if (xmlStrEqual(curNode->name, (const xmlChar *)"Address")) {
299  address = (char *) xmlNodeGetContent(curNode);
300  } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Port")) {
301  port = (char *) xmlNodeGetContent(curNode);
302  }
303  curNode = curNode->next;
304  }
305  if (address) {
306  interface = listener_push(listener, address,
307  acl_parse_family(address), port);
308  } else {
309  interface = listener_push(listener, (char *)"", AF_INET, port);
310  if (interface) {
311  interface = listener_push(listener, (char *)"", AF_INET6, port);
312  }
313  }
314  if (!interface) {
315  ods_log_error("[%s] unable to add %s:%s interface: "
316  "listener_push() failed", parser_str, address?address:"",
317  port?port:"");
318  } else {
319  ods_log_debug("[%s] added %s:%s interface to listener",
320  parser_str, address?address:"", port?port:"");
321  }
322  free((void*)port);
323  free((void*)address);
324  }
325  }
326  xmlXPathFreeObject(xpathObj);
327  xmlXPathFreeContext(xpathCtx);
328  if (doc) {
329  xmlFreeDoc(doc);
330  }
331  return listener;
332 }
333 
334 
339 const char*
340 parse_conf_string(const char* cfgfile, const char* expr, int required)
341 {
342  xmlDocPtr doc = NULL;
343  xmlXPathContextPtr xpathCtx = NULL;
344  xmlXPathObjectPtr xpathObj = NULL;
345  xmlChar *xexpr = NULL;
346  const char* string = NULL;
347 
348  ods_log_assert(expr);
349  ods_log_assert(cfgfile);
350 
351  /* Load XML document */
352  doc = xmlParseFile(cfgfile);
353  if (doc == NULL) {
354  ods_log_error("[%s] unable to parse file %s: xmlParseFile() failed",
355  parser_str, cfgfile);
356  return NULL;
357  }
358  /* Create xpath evaluation context */
359  xpathCtx = xmlXPathNewContext(doc);
360  if (xpathCtx == NULL) {
361  ods_log_error("[%s] unable to parse file %s: xmlXPathNewContext() "
362  "failed", parser_str, cfgfile);
363  xmlFreeDoc(doc);
364  return NULL;
365  }
366  /* Get string */
367  xexpr = (unsigned char*) expr;
368  xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
369  if (xpathObj == NULL || xpathObj->nodesetval == NULL ||
370  xpathObj->nodesetval->nodeNr <= 0) {
371  if (required) {
372  ods_log_error("[%s] unable to evaluate expression %s in cfgile %s",
373  parser_str, (char*) xexpr, cfgfile);
374  }
375  xmlXPathFreeContext(xpathCtx);
376  if (xpathObj) {
377  xmlXPathFreeObject(xpathObj);
378  }
379  xmlFreeDoc(doc);
380  return NULL;
381  }
382  if (xpathObj->nodesetval != NULL &&
383  xpathObj->nodesetval->nodeNr > 0) {
384  string = (const char*) xmlXPathCastToString(xpathObj);
385  xmlXPathFreeContext(xpathCtx);
386  xmlXPathFreeObject(xpathObj);
387  xmlFreeDoc(doc);
388  return string;
389  }
390  xmlXPathFreeContext(xpathCtx);
391  xmlXPathFreeObject(xpathObj);
392  xmlFreeDoc(doc);
393  return NULL;
394 }
395 
396 /*
397  * TODO all parse routines parse the complete file. Yuk!
398  * TODO make a parse_conf_bool for testing existence of empty elements
399  * instead of abusing parse_conf_string
400  * */
401 
402 const char*
403 parse_conf_zonelist_filename(const char* cfgfile)
404 {
405  int lwd = 0;
406  int lzl = 0;
407  int found = 0;
408  char* dup = NULL;
409  const char* str = parse_conf_string(
410  cfgfile,
411  "//Configuration/Enforcer/WorkingDirectory",
412  0);
413 
414  if (str) {
415  found = 1;
416  } else {
417  str = OPENDNSSEC_ENFORCER_WORKINGDIR;
418  }
419  lwd = strlen(str);
420  lzl = strlen(OPENDNSSEC_ENFORCER_ZONELIST);
421  if (lwd>0 && strncmp(str + (lwd-1), "/", 1) != 0) {
422  CHECKALLOC(dup = malloc(sizeof(char)*(lwd+lzl+2)));
423  memcpy(dup, str, sizeof(char)*(lwd+1));
424  strlcat(dup, "/", sizeof(char)*(lwd+2));
425  strlcat(dup, OPENDNSSEC_ENFORCER_ZONELIST, sizeof(char)*(lwd+lzl+2));
426  lwd += (lzl+1);
427  } else {
428  CHECKALLOC(dup = malloc(sizeof(char)*(lwd+lzl+1)));
429  memcpy(dup, str, sizeof(char)*(lwd+1));
430  strlcat(dup, OPENDNSSEC_ENFORCER_ZONELIST, sizeof(char)*(lwd+lzl+1));
431  lwd += (lzl+1);
432  }
433  if (found) {
434  free((void*)str);
435  }
436  ods_log_assert(dup);
437  return (const char*) dup;
438 }
439 
440 
441 const char*
442 parse_conf_log_filename(const char* cfgfile)
443 {
444  const char* dup = NULL;
445  const char* str = parse_conf_string(cfgfile,
446  "//Configuration/Common/Logging/Syslog/Facility",
447  0);
448  if (!str) {
449  str = parse_conf_string(cfgfile,
450  "//Configuration/Common/Logging/File/Filename",
451  0);
452  }
453  if (str) {
454  dup = strdup(str);
455  free((void*)str);
456  }
457  return dup; /* NULL, Facility or Filename */
458 }
459 
460 
461 const char*
462 parse_conf_pid_filename(const char* cfgfile)
463 {
464  const char* dup = NULL;
465  const char* str = parse_conf_string(
466  cfgfile,
467  "//Configuration/Signer/PidFile",
468  0);
469 
470  if (str) {
471  dup = strdup(str);
472  free((void*)str);
473  } else {
474  dup = strdup(ODS_SE_PIDFILE);
475  }
476  return dup;
477 }
478 
479 
480 const char*
481 parse_conf_notify_command(const char* cfgfile)
482 {
483  const char* dup = NULL;
484  const char* str = parse_conf_string(
485  cfgfile,
486  "//Configuration/Signer/NotifyCommand",
487  0);
488 
489  if (str) {
490  dup = strdup(str);
491  free((void*)str);
492  }
493  return dup;
494 }
495 
496 
497 const char*
498 parse_conf_clisock_filename(const char* cfgfile)
499 {
500  char* dup = NULL;
501  const char* str = parse_conf_string(
502  cfgfile,
503  "//Configuration/Signer/SocketFile",
504  0);
505 
506  if (str) {
507  dup = strdup(str);
508  free((void*)str);
509  } else {
510  dup = strdup(ODS_SE_SOCKFILE);
511  }
512  if (strlen(dup) >= sizeof(((struct sockaddr_un*)0)->sun_path)) {
513  dup[sizeof(((struct sockaddr_un*)0)->sun_path)-1] = '\0'; /* don't worry about just a few bytes 'lost' */
514  ods_log_warning("[%s] SocketFile path too long, truncated to %s", parser_str, dup);
515  }
516  return dup;
517 }
518 
519 
520 const char*
521 parse_conf_working_dir(const char* cfgfile)
522 {
523  const char* dup = NULL;
524  const char* str = parse_conf_string(
525  cfgfile,
526  "//Configuration/Signer/WorkingDirectory",
527  0);
528 
529  if (str) {
530  dup = strdup(str);
531  free((void*)str);
532  } else {
533  dup = strdup(ODS_SE_WORKDIR);
534  }
535  ods_log_assert(dup);
536  return dup;
537 }
538 
539 
540 const char*
541 parse_conf_username(const char* cfgfile)
542 {
543  const char* dup = NULL;
544  const char* str = parse_conf_string(
545  cfgfile,
546  "//Configuration/Signer/Privileges/User",
547  0);
548 
549  if (str) {
550  dup = strdup(str);
551  free((void*)str);
552  }
553  return dup;
554 }
555 
556 
557 const char*
558 parse_conf_group(const char* cfgfile)
559 {
560  const char* dup = NULL;
561  const char* str = parse_conf_string(
562  cfgfile,
563  "//Configuration/Signer/Privileges/Group",
564  0);
565 
566  if (str) {
567  dup = strdup(str);
568  free((void*)str);
569  }
570  return dup;
571 }
572 
573 
574 const char*
575 parse_conf_chroot(const char* cfgfile)
576 {
577  const char* dup = NULL;
578  const char* str = parse_conf_string(
579  cfgfile,
580  "//Configuration/Signer/Privileges/Directory",
581  0);
582 
583  if (str) {
584  dup = strdup(str);
585  free((void*)str);
586  }
587  return dup;
588 }
589 
590 
595 int
596 parse_conf_use_syslog(const char* cfgfile)
597 {
598  const char* str = parse_conf_string(cfgfile,
599  "//Configuration/Common/Logging/Syslog/Facility",
600  0);
601  if (str) {
602  free((void*)str);
603  return 1;
604  }
605  return 0;
606 }
607 
608 int
609 parse_conf_verbosity(const char* cfgfile)
610 {
611  int verbosity = ODS_SE_VERBOSITY;
612  const char* str = parse_conf_string(cfgfile,
613  "//Configuration/Common/Logging/Verbosity",
614  0);
615  if (str) {
616  if (strlen(str) > 0) {
617  verbosity = atoi(str);
618  }
619  free((void*)str);
620  }
621  return verbosity;
622 }
623 
624 
625 int
626 parse_conf_worker_threads(const char* cfgfile)
627 {
628  int numwt = ODS_SE_WORKERTHREADS;
629  const char* str = parse_conf_string(cfgfile,
630  "//Configuration/Signer/WorkerThreads",
631  0);
632  if (str) {
633  if (strlen(str) > 0) {
634  numwt = atoi(str);
635  }
636  free((void*)str);
637  }
638  return numwt;
639 }
640 
641 
642 int
643 parse_conf_signer_threads(const char* cfgfile)
644 {
645  int numwt = ODS_SE_WORKERTHREADS;
646  const char* str = parse_conf_string(cfgfile,
647  "//Configuration/Signer/SignerThreads",
648  0);
649  if (str) {
650  if (strlen(str) > 0) {
651  numwt = atoi(str);
652  }
653  free((void*)str);
654  return numwt;
655  }
656  /* no SignerThreads value configured, look at WorkerThreads */
657  return parse_conf_worker_threads(cfgfile);
658 }
int parse_conf_worker_threads(const char *cfgfile)
Definition: confparser.c:626
int parse_conf_use_syslog(const char *cfgfile)
Definition: confparser.c:596
const char * parse_conf_clisock_filename(const char *cfgfile)
Definition: confparser.c:498
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
const char * parse_conf_working_dir(const char *cfgfile)
Definition: confparser.c:521
const char * parse_conf_group(const char *cfgfile)
Definition: confparser.c:558
int parse_conf_signer_threads(const char *cfgfile)
Definition: confparser.c:643
const char * parse_conf_log_filename(const char *cfgfile)
Definition: confparser.c:442
const char * parse_conf_chroot(const char *cfgfile)
Definition: confparser.c:575
listener_type * listener_create()
Definition: listener.c:45
const char * parse_conf_string(const char *cfgfile, const char *expr, int required)
Definition: confparser.c:340
listener_type * parse_conf_listener(const char *cfgfile)
Definition: confparser.c:248
const char * parse_conf_username(const char *cfgfile)
Definition: confparser.c:541
int parse_conf_verbosity(const char *cfgfile)
Definition: confparser.c:609
hsm_repository_t * parse_conf_repositories(const char *cfgfile)
Definition: confparser.c:143
const char * parse_conf_notify_command(const char *cfgfile)
Definition: confparser.c:481
const char * parse_conf_zonelist_filename(const char *cfgfile)
Definition: confparser.c:403
const char * parse_conf_pid_filename(const char *cfgfile)
Definition: confparser.c:462
interface_type * listener_push(listener_type *listener, char *address, int family, char *port)
Definition: listener.c:60