OpenDNSSEC-signer  1.3.9
confparser.c
Go to the documentation of this file.
1 /*
2  * $Id: confparser.c 6256 2012-04-10 14:28:55Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "parser/confparser.h"
35 #include "parser/zonelistparser.h"
36 #include "shared/allocator.h"
37 #include "shared/file.h"
38 #include "shared/log.h"
39 #include "shared/status.h"
40 
41 #include <libxml/xpath.h>
42 #include <libxml/relaxng.h>
43 #include <libxml/xmlreader.h>
44 #include <string.h>
45 #include <stdlib.h>
46 
47 static const char* parser_str = "parser";
48 
49 
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  ods_log_error("[%s] no cfgfile or rngfile", parser_str);
66  return ODS_STATUS_ASSERT_ERR;
67  }
68  ods_log_assert(cfgfile);
69  ods_log_assert(rngfile);
70  ods_log_debug("[%s] check cfgfile %s with rngfile %s", parser_str,
71  cfgfile, rngfile);
72 
73  /* Load XML document */
74  doc = xmlParseFile(cfgfile);
75  if (doc == NULL) {
76  ods_log_error("[%s] unable to read cfgfile %s", parser_str,
77  cfgfile);
78  return ODS_STATUS_XML_ERR;
79  }
80  /* Load rng document */
81  rngdoc = xmlParseFile(rngfile);
82  if (rngdoc == NULL) {
83  ods_log_error("[%s] unable to read rngfile %s", parser_str,
84  rngfile);
85  xmlFreeDoc(doc);
86  return ODS_STATUS_XML_ERR;
87  }
88  /* Create an XML RelaxNGs parser context for the relax-ng document. */
89  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
90  if (rngpctx == NULL) {
91  xmlFreeDoc(rngdoc);
92  xmlFreeDoc(doc);
93  ods_log_error("[%s] unable to create XML RelaxNGs parser context",
94  parser_str);
95  return ODS_STATUS_XML_ERR;
96  }
97  /* Parse a schema definition resource and
98  * build an internal XML schema structure.
99  */
100  schema = xmlRelaxNGParse(rngpctx);
101  if (schema == NULL) {
102  ods_log_error("[%s] unable to parse a schema definition resource",
103  parser_str);
104  xmlRelaxNGFreeParserCtxt(rngpctx);
105  xmlFreeDoc(rngdoc);
106  xmlFreeDoc(doc);
107  return ODS_STATUS_PARSE_ERR;
108  }
109  /* Create an XML RelaxNGs validation context. */
110  rngctx = xmlRelaxNGNewValidCtxt(schema);
111  if (rngctx == NULL) {
112  ods_log_error("[%s] unable to create RelaxNGs validation context",
113  parser_str);
114  xmlRelaxNGFree(schema);
115  xmlRelaxNGFreeParserCtxt(rngpctx);
116  xmlFreeDoc(rngdoc);
117  xmlFreeDoc(doc);
118  return ODS_STATUS_RNG_ERR;
119  }
120  /* Validate a document tree in memory. */
121  status = xmlRelaxNGValidateDoc(rngctx,doc);
122  if (status != 0) {
123  ods_log_error("[%s] cfgfile validation failed %s", parser_str,
124  cfgfile);
125  xmlRelaxNGFreeValidCtxt(rngctx);
126  xmlRelaxNGFree(schema);
127  xmlRelaxNGFreeParserCtxt(rngpctx);
128  xmlFreeDoc(rngdoc);
129  xmlFreeDoc(doc);
130  return ODS_STATUS_RNG_ERR;
131  }
132  xmlRelaxNGFreeValidCtxt(rngctx);
133  xmlRelaxNGFree(schema);
134  xmlRelaxNGFreeParserCtxt(rngpctx);
135  xmlFreeDoc(rngdoc);
136  xmlFreeDoc(doc);
137  return ODS_STATUS_OK;
138 }
139 
140 /* TODO: look how the enforcer reads this now */
141 
142 
147 adapter_type**
148 parse_conf_adapters(allocator_type* allocator, const char* cfgfile,
149  int* count)
150 {
151  char* tag_name = NULL;
152  adapter_type** adapters = NULL;
153  int ret = 0;
154  size_t adcount = 0;
155 
156  xmlTextReaderPtr reader = NULL;
157  xmlDocPtr doc = NULL;
158  xmlXPathContextPtr xpathCtx = NULL;
159 
160  xmlChar* expr = (xmlChar*) "//Adapter";
161 
162  ods_log_assert(allocator);
163  ods_log_assert(cfgfile);
164 
165  reader = xmlNewTextReaderFilename(cfgfile);
166  if (!reader) {
167  ods_log_error("[%s] unable to open file %s", parser_str, cfgfile);
168  return NULL;
169  }
170 
171  ret = xmlTextReaderRead(reader);
172  adapters = (adapter_type**) allocator_alloc(allocator,
173  ADMAX * sizeof(adapter_type*));
174  while (ret == XML_READER_TYPE_ELEMENT) {
175  if (adcount >= ADMAX) {
176  ods_log_warning("[%s] too many adapters in config file %s, "
177  "skipping additional adapters", parser_str, cfgfile);
178  break;
179  }
180 
181  tag_name = (char*) xmlTextReaderLocalName(reader);
182 
183  /* This assumes that there is no other <Adapters> element in
184  * conf.xml
185  */
186  if (ods_strcmp(tag_name, "Adapter") == 0 &&
187  ods_strcmp(tag_name, "Adapters") != 0 &&
188  xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
189  /* Found an adapter */
190 
191  /* Expand this node to get the rest of the info */
192  xmlTextReaderExpand(reader);
193  doc = xmlTextReaderCurrentDoc(reader);
194  if (doc) {
195  xpathCtx = xmlXPathNewContext(doc);
196  }
197  if (doc == NULL || xpathCtx == NULL) {
198  ods_log_error("[%s] unable to read adapter; skipping",
199  parser_str);
200  ret = xmlTextReaderRead(reader);
201  free((void*) tag_name);
202  continue;
203  }
204  /* That worked, reuse the parse_zonelist_adapter() function */
205  adapters[adcount] = parse_zonelist_adapter(xpathCtx, expr, 1);
206  adcount++;
207  ods_log_debug("[%s] adapter added", parser_str);
208  xmlXPathFreeContext(xpathCtx);
209  }
210  free((void*) tag_name);
211  ret = xmlTextReaderRead(reader);
212  }
213 
214  /* no more adapters */
215  ods_log_debug("[%s] no more adapters", parser_str);
216  xmlFreeTextReader(reader);
217  if (doc) {
218  xmlFreeDoc(doc);
219  }
220  if (ret != 0) {
221  ods_log_error("[%s] error parsing file %s", parser_str, cfgfile);
222  return NULL;
223  }
224  *count = (int) adcount;
225  return adapters;
226 }
227 
228 
233 const char*
234 parse_conf_string(const char* cfgfile, const char* expr, int required)
235 {
236  xmlDocPtr doc = NULL;
237  xmlXPathContextPtr xpathCtx = NULL;
238  xmlXPathObjectPtr xpathObj = NULL;
239  xmlChar *xexpr = NULL;
240  const char* string = NULL;
241 
242  ods_log_assert(expr);
243  ods_log_assert(cfgfile);
244 
245  /* Load XML document */
246  doc = xmlParseFile(cfgfile);
247  if (doc == NULL) {
248  return NULL;
249  }
250  /* Create xpath evaluation context */
251  xpathCtx = xmlXPathNewContext(doc);
252  if (xpathCtx == NULL) {
253  ods_log_error("[%s] unable to create new XPath context for cfgile "
254  "%s expr %s", parser_str, cfgfile, (char*) expr);
255  xmlFreeDoc(doc);
256  return NULL;
257  }
258  /* Get string */
259  xexpr = (unsigned char*) expr;
260  xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
261  if (xpathObj == NULL || xpathObj->nodesetval == NULL ||
262  xpathObj->nodesetval->nodeNr <= 0) {
263  if (required) {
264  ods_log_error("[%s] unable to evaluate required element %s in "
265  "cfgfile %s", parser_str, (char*) xexpr, cfgfile);
266  }
267  xmlXPathFreeContext(xpathCtx);
268  if (xpathObj) {
269  xmlXPathFreeObject(xpathObj);
270  }
271  xmlFreeDoc(doc);
272  return NULL;
273  }
274  if (xpathObj->nodesetval != NULL &&
275  xpathObj->nodesetval->nodeNr > 0) {
276  string = (const char*) xmlXPathCastToString(xpathObj);
277  xmlXPathFreeContext(xpathCtx);
278  xmlXPathFreeObject(xpathObj);
279  xmlFreeDoc(doc);
280  return string;
281  }
282  xmlXPathFreeContext(xpathCtx);
283  xmlXPathFreeObject(xpathObj);
284  xmlFreeDoc(doc);
285  return NULL;
286 }
287 
288 
289 const char*
290 parse_conf_zonelist_filename(allocator_type* allocator, const char* cfgfile)
291 {
292  const char* dup = NULL;
293  const char* str = parse_conf_string(
294  cfgfile,
295  "//Configuration/Common/ZoneListFile",
296  1);
297 
298  if (str) {
299  dup = allocator_strdup(allocator, str);
300  free((void*)str);
301  }
302  return dup;
303 }
304 
305 
306 const char*
307 parse_conf_zonefetch_filename(allocator_type* allocator, const char* cfgfile)
308 {
309  const char* dup = NULL;
310  const char* str = parse_conf_string(
311  cfgfile,
312  "//Configuration/Common/ZoneFetchFile",
313  0);
314 
315  if (str) {
316  dup = allocator_strdup(allocator, str);
317  free((void*)str);
318  }
319  return dup;
320 }
321 
322 
323 const char*
324 parse_conf_log_filename(allocator_type* allocator, const char* cfgfile)
325 {
326  const char* dup = NULL;
327  const char* str = parse_conf_string(cfgfile,
328  "//Configuration/Common/Logging/Syslog/Facility",
329  0);
330  if (!str) {
331  str = parse_conf_string(cfgfile,
332  "//Configuration/Common/Logging/File/Filename",
333  0);
334  }
335  if (str) {
336  dup = allocator_strdup(allocator, str);
337  free((void*)str);
338  }
339  return dup; /* NULL, Facility or Filename */
340 }
341 
342 
343 const char*
344 parse_conf_pid_filename(allocator_type* allocator, const char* cfgfile)
345 {
346  const char* dup = NULL;
347  const char* str = parse_conf_string(
348  cfgfile,
349  "//Configuration/Signer/PidFile",
350  0);
351 
352  if (str) {
353  dup = allocator_strdup(allocator, str);
354  free((void*)str);
355  } else {
356  dup = allocator_strdup(allocator, ODS_SE_PIDFILE);
357  }
358  return dup;
359 }
360 
361 
362 const char*
363 parse_conf_notify_command(allocator_type* allocator, const char* cfgfile)
364 {
365  const char* dup = NULL;
366  const char* str = parse_conf_string(
367  cfgfile,
368  "//Configuration/Signer/NotifyCommand",
369  0);
370 
371  if (str) {
372  dup = allocator_strdup(allocator, str);
373  free((void*)str);
374  }
375  return dup;
376 }
377 
378 
379 const char*
380 parse_conf_clisock_filename(allocator_type* allocator, const char* cfgfile)
381 {
382  const char* dup = NULL;
383  const char* str = parse_conf_string(
384  cfgfile,
385  "//Configuration/Signer/SocketFile",
386  0);
387 
388  if (str) {
389  dup = allocator_strdup(allocator, str);
390  free((void*)str);
391  } else {
392  dup = allocator_strdup(allocator, ODS_SE_SOCKFILE);
393  }
394  return dup;
395 }
396 
397 
398 const char*
399 parse_conf_working_dir(allocator_type* allocator, const char* cfgfile)
400 {
401  const char* dup = NULL;
402  const char* str = parse_conf_string(
403  cfgfile,
404  "//Configuration/Signer/WorkingDirectory",
405  0);
406 
407  if (str) {
408  dup = allocator_strdup(allocator, str);
409  free((void*)str);
410  } else {
411  dup = allocator_strdup(allocator, ODS_SE_WORKDIR);
412  }
413  return dup;
414 }
415 
416 
417 const char*
418 parse_conf_username(allocator_type* allocator, const char* cfgfile)
419 {
420  const char* dup = NULL;
421  const char* str = parse_conf_string(
422  cfgfile,
423  "//Configuration/Signer/Privileges/User",
424  0);
425 
426  if (str) {
427  dup = allocator_strdup(allocator, str);
428  free((void*)str);
429  }
430  return dup;
431 }
432 
433 
434 const char*
435 parse_conf_group(allocator_type* allocator, const char* cfgfile)
436 {
437  const char* dup = NULL;
438  const char* str = parse_conf_string(
439  cfgfile,
440  "//Configuration/Signer/Privileges/Group",
441  0);
442 
443  if (str) {
444  dup = allocator_strdup(allocator, str);
445  free((void*)str);
446  }
447  return dup;
448 }
449 
450 
451 const char*
452 parse_conf_chroot(allocator_type* allocator, const char* cfgfile)
453 {
454  const char* dup = NULL;
455  const char* str = parse_conf_string(
456  cfgfile,
457  "//Configuration/Signer/Privileges/Directory",
458  0);
459 
460  if (str) {
461  dup = allocator_strdup(allocator, str);
462  free((void*)str);
463  }
464  return dup;
465 }
466 
467 
472 int
473 parse_conf_use_syslog(const char* cfgfile)
474 {
475  const char* str = parse_conf_string(cfgfile,
476  "//Configuration/Common/Logging/Syslog/Facility",
477  0);
478  if (str) {
479  free((void*)str);
480  return 1;
481  }
482  return 0;
483 }
484 
485 int
486 parse_conf_verbosity(const char* cfgfile)
487 {
488  int verbosity = ODS_SE_VERBOSITY;
489  const char* str = parse_conf_string(cfgfile,
490  "//Configuration/Common/Logging/Verbosity",
491  0);
492  if (str) {
493  if (strlen(str) > 0) {
494  verbosity = atoi(str);
495  }
496  free((void*)str);
497  }
498  return verbosity;
499 }
500 
501 
502 int
503 parse_conf_worker_threads(const char* cfgfile)
504 {
505  int numwt = ODS_SE_WORKERTHREADS;
506  const char* str = parse_conf_string(cfgfile,
507  "//Configuration/Signer/WorkerThreads",
508  0);
509  if (str) {
510  if (strlen(str) > 0) {
511  numwt = atoi(str);
512  }
513  free((void*)str);
514  }
515  return numwt;
516 }
517 
518 
519 int
520 parse_conf_signer_threads(const char* cfgfile)
521 {
522  int numwt = ODS_SE_WORKERTHREADS;
523  const char* str = parse_conf_string(cfgfile,
524  "//Configuration/Signer/SignerThreads",
525  0);
526  if (str) {
527  if (strlen(str) > 0) {
528  numwt = atoi(str);
529  }
530  free((void*)str);
531  return numwt;
532  }
533  /* no SignerThreads value configured, look at WorkerThreads */
534  return parse_conf_worker_threads(cfgfile);
535 }