OpenDNSSEC-enforcer  1.4.6
daemon_util.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. 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 
27 /*
28  * daemon_util.c code needed to get a daemon up and running
29  *
30  * edit the DAEMONCONFIG and cmlParse function
31  * in daemon_util.[c|h] to add options specific
32  * to your app
33  *
34  * gcc -o daemon daemon_util.c daemon.c
35  *
36  * Most of this is based on stuff I have seen in NSD
37  */
38 #include "config.h"
39 
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <syslog.h>
48 #include <stdarg.h>
49 #include <errno.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <ctype.h>
53 #include <signal.h>
54 #include <fcntl.h>
55 #include <syslog.h>
56 
57 #include <sys/select.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 
61 #include <libxml/tree.h>
62 #include <libxml/parser.h>
63 #include <libxml/xpath.h>
64 #include <libxml/xpathInternals.h>
65 #include <libxml/relaxng.h>
66 
67 #include "daemon.h"
68 #include "daemon_util.h"
69 
70 #include "ksm/database.h"
71 #include "ksm/datetime.h"
72 #include "ksm/string_util.h"
73 #include "ksm/string_util2.h"
74 
75 
81 #if defined(HAVE_SYSLOG_R) && defined(HAVE_OPENLOG_R) && defined(HAVE_CLOSELOG_R) && defined(HAVE_VSYSLOG_R)
82 struct syslog_data sdata = SYSLOG_DATA_INIT;
83 #else
84 #undef HAVE_SYSLOG_R
85 #undef HAVE_OPENLOG_R
86 #undef HAVE_CLOSELOG_R
87 #undef HAVE_VSYSLOG_R
88 #endif
89 
90  int
92 {
93  int status = 0;
94 
95  xmlDocPtr doc = NULL;
96  xmlDocPtr rngdoc = NULL;
97  xmlXPathContextPtr xpathCtx = NULL;
98  xmlXPathObjectPtr xpathObj = NULL;
99  xmlRelaxNGParserCtxtPtr rngpctx = NULL;
100  xmlRelaxNGValidCtxtPtr rngctx = NULL;
101  xmlRelaxNGPtr schema = NULL;
102  xmlChar *user_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/User";
103  xmlChar *group_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/Group";
104 
105  char* filename = NULL;
106  char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
107  char* temp_char = NULL;
108 
109  struct passwd *pwd;
110  struct group *grp;
111 
112  FILE *file;
113 
114  if (config->configfile != NULL) {
115  filename = StrStrdup(config->configfile);
116  } else {
117  filename = StrStrdup(OPENDNSSEC_CONFIG_FILE);
118  }
119 
120  /* Load XML document */
121  doc = xmlParseFile(filename);
122  if (doc == NULL) {
123  /* To get a better error message try to open the file */
124  file = fopen(filename, "r");
125  if (file == NULL) {
126  log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", filename);
127  } else {
128  log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", filename);
129  fclose(file);
130  }
131  return(-1);
132  }
133 
134  /* Load rng document */
135  rngdoc = xmlParseFile(rngfilename);
136  if (rngdoc == NULL) {
137  /* To get a better error message try to open the file */
138  file = fopen(rngfilename, "r");
139  if (file == NULL) {
140  log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", rngfilename);
141  } else {
142  log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", rngfilename);
143  fclose(file);
144  }
145  return(-1);
146  }
147 
148  /* Create an XML RelaxNGs parser context for the relax-ng document. */
149  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
150  if (rngpctx == NULL) {
151  log_msg(config, LOG_ERR, "Error: unable to create XML RelaxNGs parser context");
152  return(-1);
153  }
154 
155  /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
156  schema = xmlRelaxNGParse(rngpctx);
157  if (schema == NULL) {
158  log_msg(config, LOG_ERR, "Error: unable to parse a schema definition resource");
159  return(-1);
160  }
161 
162  /* Create an XML RelaxNGs validation context based on the given schema */
163  rngctx = xmlRelaxNGNewValidCtxt(schema);
164  if (rngctx == NULL) {
165  log_msg(config, LOG_ERR, "Error: unable to create RelaxNGs validation context based on the schema");
166  return(-1);
167  }
168 
169  xmlRelaxNGSetValidErrors(rngctx,
170  (xmlRelaxNGValidityErrorFunc) log_xml_error,
171  (xmlRelaxNGValidityWarningFunc) log_xml_warn,
172  NULL);
173 
174  /* Validate a document tree in memory. */
175  status = xmlRelaxNGValidateDoc(rngctx,doc);
176  if (status != 0) {
177  log_msg(config, LOG_ERR, "Error validating file \"%s\"", filename);
178  return(-1);
179  }
180 
181  /* Now parse a value out of the conf */
182  /* Create xpath evaluation context */
183  xpathCtx = xmlXPathNewContext(doc);
184  if(xpathCtx == NULL) {
185  log_msg(config, LOG_ERR,"Error: unable to create new XPath context");
186  xmlFreeDoc(doc);
187  return(-1);
188  }
189 
190  /* Set the group if specified */
191  xpathObj = xmlXPathEvalExpression(group_expr, xpathCtx);
192  if(xpathObj == NULL) {
193  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", group_expr);
194  xmlXPathFreeContext(xpathCtx);
195  xmlFreeDoc(doc);
196  return(-1);
197  }
198  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
199  temp_char = (char*) xmlXPathCastToString(xpathObj);
200  StrAppend(&config->groupname, temp_char);
201  StrFree(temp_char);
202  } else {
203  config->groupname = NULL;
204  }
205  xmlXPathFreeObject(xpathObj);
206 
207  /* Set the user to drop to if specified */
208  xpathObj = xmlXPathEvalExpression(user_expr, xpathCtx);
209  if(xpathObj == NULL) {
210  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", user_expr);
211  xmlXPathFreeContext(xpathCtx);
212  xmlFreeDoc(doc);
213  return(-1);
214  }
215  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
216  temp_char = (char*) xmlXPathCastToString(xpathObj);
217  StrAppend(&config->username, temp_char);
218  StrFree(temp_char);
219  } else {
220  config->username = NULL;
221  }
222  xmlXPathFreeObject(xpathObj);
223 
224  /* Set uid and gid if required */
225  if (config->username != NULL) {
226  /* Lookup the user id in /etc/passwd */
227  if ((pwd = getpwnam(config->username)) == NULL) {
228 #ifdef HAVE_SYSLOG_R
229  syslog_r(LOG_ERR, &sdata, "user '%s' does not exist. exiting...\n", config->username);
230 #else
231  syslog(LOG_ERR, "user '%s' does not exist. exiting...\n", config->username);
232 #endif
233  exit(1);
234  } else {
235  config->uid = pwd->pw_uid;
236  }
237  endpwent();
238  }
239  if (config->groupname) {
240  /* Lookup the group id in /etc/groups */
241  if ((grp = getgrnam(config->groupname)) == NULL) {
242 #ifdef HAVE_SYSLOG_R
243  syslog_r(LOG_ERR, &sdata, "group '%s' does not exist. exiting...\n", config->groupname);
244 #else
245  syslog(LOG_ERR, "group '%s' does not exist. exiting...\n", config->groupname);
246 #endif
247  exit(1);
248  } else {
249  config->gid = grp->gr_gid;
250  }
251  endgrent();
252  }
253 
254  xmlRelaxNGFree(schema);
255  xmlRelaxNGFreeValidCtxt(rngctx);
256  xmlRelaxNGFreeParserCtxt(rngpctx);
257  xmlFreeDoc(doc);
258  xmlFreeDoc(rngdoc);
259  StrFree(filename);
260 
261  return 0;
262 }
263 
264 /* Set up logging as per default (facility may be switched based on config file) */
265 void log_init(int facility, const char *program_name)
266 {
267 #ifdef HAVE_OPENLOG_R
268  openlog_r(program_name, 0, facility, &sdata);
269 #else
270  openlog(program_name, 0, facility);
271 #endif
272 }
273 
274 /* Switch log to new facility */
275 void log_switch(int facility, const char *facility_name, const char *program_name, int verbose)
276 {
277 #ifdef HAVE_CLOSELOG_R
278  closelog_r(&sdata);
279 #else
280  closelog();
281 #endif
282 #ifdef HAVE_OPENLOG_R
283  openlog_r(program_name, 0, facility, &sdata);
284 #else
285  openlog(program_name, 0, facility);
286 #endif
287  if (verbose) {
288  log_msg(NULL, LOG_INFO, "Switched log facility to: %s", facility_name);
289  }
290 }
291 
292 
293 void
294 log_msg(DAEMONCONFIG *config, int priority, const char *format, ...)
295 {
296  /* If the variable arg list is bad then random errors can occur */
297  va_list args;
298  if (config && config->debug) priority = LOG_ERR;
299  va_start(args, format);
300 
301 #ifdef HAVE_VSYSLOG_R
302  vsyslog_r(priority, &sdata, format, args);
303 #else
304  vsyslog(priority, format, args);
305 #endif
306  va_end(args);
307 }
308 
309 /*
310  * log function suitable for libksm callback
311  */
312  void
313 ksm_log_msg(const char *format)
314 {
315  if (strncmp(format, "ERROR:", 6) == 0) {
316 #ifdef HAVE_SYSLOG_R
317  syslog_r(LOG_ERR, &sdata, "%s", format);
318 #else
319  syslog(LOG_ERR, "%s", format);
320 #endif
321  }
322  else if (strncmp(format, "INFO:", 5) == 0) {
323 #ifdef HAVE_SYSLOG_R
324  syslog_r(LOG_INFO, &sdata, "%s", format);
325 #else
326  syslog(LOG_INFO, "%s", format);
327 #endif
328  }
329  else if (strncmp(format, "WARNING:", 8) == 0) {
330 #ifdef HAVE_SYSLOG_R
331  syslog_r(LOG_WARNING, &sdata, "%s", format);
332 #else
333  syslog(LOG_WARNING, "%s", format);
334 #endif
335  }
336  else if (strncmp(format, "DEBUG:", 6) == 0) {
337 #ifdef HAVE_SYSLOG_R
338  syslog_r(LOG_DEBUG, &sdata, "%s", format);
339 #else
340  syslog(LOG_DEBUG, "%s", format);
341 #endif
342  }
343  else {
344 #ifdef HAVE_SYSLOG_R
345  syslog_r(LOG_ERR, &sdata, "%s", format);
346 #else
347  syslog(LOG_ERR, "%s", format);
348 #endif
349  }
350 }
351 
352 /* XML Error Message */
353  void
354 log_xml_error(void *ignore, const char *format, ...)
355 {
356  va_list args;
357 
358  (void) ignore;
359 
360  /* If the variable arg list is bad then random errors can occur */
361  va_start(args, format);
362 #ifdef HAVE_VSYSLOG_R
363  vsyslog_r(LOG_ERR, &sdata, format, args);
364 #else
365  vsyslog(LOG_ERR, format, args);
366 #endif
367  va_end(args);
368 }
369 
370 /* XML Warning Message */
371  void
372 log_xml_warn(void *ignore, const char *format, ...)
373 {
374  va_list args;
375 
376  (void) ignore;
377 
378  /* If the variable arg list is bad then random errors can occur */
379  va_start(args, format);
380 #ifdef HAVE_VSYSLOG_R
381  vsyslog_r(LOG_INFO, &sdata, format, args);
382 #else
383  vsyslog(LOG_INFO, format, args);
384 #endif
385  va_end(args);
386 }
387 
388  static void
389 usage(const char* prog)
390 {
391  fprintf(stderr, "Usage: %s [OPTION]...\n", prog);
392  fprintf(stderr, "OpenDNSSEC Enforcer version %s\n\n", VERSION);
393  fprintf(stderr, "Supported options:\n");
394  fprintf(stderr, " -c <file> Use alternate conf.xml.\n");
395  fprintf(stderr, " -d Debug.\n");
396  fprintf(stderr, " -1 Run once, then exit.\n");
397  fprintf(stderr, " -p <policy> Run once processing only the specified policy, then exit.\n");
398 /* fprintf(stderr, " -u user Change effective uid to the specified user.\n");*/
399  fprintf(stderr, " -P <pidfile> Specify the PID file to write.\n");
400 
401  fprintf(stderr, " -V Print version.\n");
402  fprintf(stderr, " -[?|h] This help.\n");
403 }
404 
405  static void
406 version(void)
407 {
408  fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
409  fprintf(stderr, "Written by %s.\n\n", AUTHOR_NAME);
410  fprintf(stderr, "%s. This is free software.\n", COPYRIGHT_STR);
411  fprintf(stderr, "See source files for more license information\n");
412  exit(0);
413 }
414 
415  int
416 write_data(DAEMONCONFIG *config, FILE *file, const void *data, size_t size)
417 {
418  size_t result;
419 
420  if (size == 0)
421  return 1;
422 
423  result = fwrite(data, 1, size, file);
424 
425  if (result == 0) {
426  log_msg(config, LOG_ERR, "write failed: %s", strerror(errno));
427  return 0;
428  } else if (result < size) {
429  log_msg(config, LOG_ERR, "short write (disk full?)");
430  return 0;
431  } else {
432  return 1;
433  }
434 }
435 
436  static pid_t
437 readpid(const char *file)
438 {
439  int fd;
440  pid_t pid;
441  char pidbuf[32];
442  char *t;
443  int l;
444 
445  if ((fd = open(file, O_RDONLY)) == -1) {
446  return -1;
447  }
448  if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
449  close(fd);
450  return -1;
451  }
452  close(fd);
453  /* Empty pidfile means no pidfile... */
454  if (l == 0) {
455  errno = ENOENT;
456  return -1;
457  }
458  pid = strtol(pidbuf, &t, 10);
459 
460  if (*t && *t != '\n') {
461  return -1;
462  }
463  return pid;
464 }
465 
466  int
468 {
469  FILE * fd;
470  char pidbuf[32];
471  struct stat stat_ret;
472  pid_t oldpid;
473 
474  /* If the file exists then either we didn't shutdown cleanly or an enforcer is
475  * already running; in either case shutdown */
476  if (stat(config->pidfile, &stat_ret) != 0) {
477 
478  if (errno != ENOENT) {
479  log_msg(config, LOG_ERR, "cannot stat pidfile %s: %s",
480  config->pidfile, strerror(errno));
481  return -1;
482  }
483  } else {
484  if (S_ISREG(stat_ret.st_mode)) {
485  /* The file exists already */
486  if ((oldpid = readpid(config->pidfile)) == -1) {
487  /* consider stale pidfile */
488  if (errno != ENOENT) {
489  log_msg(config, LOG_ERR, "cannot read pidfile %s: %s",
490  config->pidfile, strerror(errno));
491  }
492  } else {
493  if (kill(oldpid, 0) == 0 || errno == EPERM) {
494  log_msg(config, LOG_ERR, "pidfile %s already exists, "
495  "a process with pid %u is already running. "
496  "If no ods-enforcerd process is running, a previous "
497  "instance didn't shutdown cleanly, please remove this "
498  "file and try again.", config->pidfile, oldpid);
499  exit(1);
500  } else {
501  log_msg(config, LOG_WARNING, "pidfile %s already exists, "
502  "but no process with pid %u is running. "
503  "A previous instance didn't shutdown cleanly, this "
504  "pidfile is stale.", config->pidfile, oldpid);
505  }
506  }
507  }
508  }
509 
510  /* All good, carry on */
511  snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) config->pid);
512 
513  if ((fd = fopen(config->pidfile, "w")) == NULL ) {
514  return -1;
515  }
516 
517  if (!write_data(config, fd, pidbuf, strlen(pidbuf))) {
518  fclose(fd);
519  return -1;
520  }
521  fclose(fd);
522 
523  if (chown(config->pidfile, config->uid, config->gid) == -1) {
524  log_msg(config, LOG_ERR, "cannot chown(%u,%u) %s: %s",
525  (unsigned) config->uid, (unsigned) config->gid,
526  config->pidfile, strerror(errno));
527  return -1;
528  }
529 
530  /* Mark this our pidfile so exit_function unlink's it */
531  daemon_our_pidfile = 1;
532  return 0;
533 }
534 
535  int
537 {
538  char* directory = NULL;
539  char* slash;
540  struct stat stat_ret;
541  char *path = getenv("PWD");
542 
543  /* Find the directory part of the (fully qualified) pidfile */
544  if (*config->pidfile != '/') {
545  StrAppend(&directory, path);
546  StrAppend(&directory, "/");
547  StrAppend(&directory, config->pidfile);
548  } else {
549  directory = StrStrdup(config->pidfile);
550  }
551  slash = strrchr(directory, '/');
552  *slash = 0;
553 
554  /* Check that it exists */
555  if (stat(directory, &stat_ret) != 0) {
556 
557  if (errno != ENOENT) {
558  log_msg(config, LOG_ERR, "cannot stat directory %s: %s",
559  directory, strerror(errno));
560  return -1;
561  }
562  }
563 
564  if (S_ISDIR(stat_ret.st_mode)) {
565  /* Do nothing, the directory exists already */
566  } else {
567  /* try to create it */
568  if (make_directory(config, directory) != 0) {
569  StrFree(directory);
570  return -1;
571  }
572  }
573  StrFree(directory);
574 
575  return 0;
576 }
577 
578 int make_directory(DAEMONCONFIG* config, const char* path) {
579 
580  char* parent;
581  char* slash;
582  struct stat stat_ret;
583 
584  parent = StrStrdup(path);
585  slash = strrchr(parent, '/');
586 
587  *slash = 0;
588 
589  if (stat(parent, &stat_ret) != 0) {
590  if (errno != ENOENT) {
591  log_msg(NULL, LOG_ERR, "cannot stat %s: %s\n",
592  parent, strerror(errno));
593  return 1;
594  }
595  }
596 
597  if (!S_ISDIR(stat_ret.st_mode)) {
598  make_directory(config, parent);
599  }
600 
601 
602  StrFree(parent);
603 
604  if (mkdir(path, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != 0) {
605  log_msg(NULL, LOG_ERR, "cannot create directory %s: %s\n",
606  path, strerror(errno));
607  return 1;
608  }
609 
610 
611  if (chown(path, config->uid, config->gid) == -1) {
612  log_msg(config, LOG_ERR, "cannot chown(%u,%u) %s: %s",
613  (unsigned) config->uid, (unsigned) config->gid,
614  path, strerror(errno));
615  return 1;
616  }
617 
618  return 0;
619 
620 }
621 
622  void
623 cmdlParse(DAEMONCONFIG* config, int *argc, char **argv)
624 {
625  int c;
626 
627  /*
628  * Read the command line
629  */
630  while ((c = getopt(*argc, argv, "1c:hdV?u:P:p:")) != -1) {
631  switch (c) {
632  case '1':
633  config->once = true;
634  break;
635  case 'c':
636  config->configfile = optarg;
637  break;
638  case 'd':
639  config->debug = true;
640  break;
641  case 'P':
642  config->pidfile = optarg;
643  config->pidfile_set = 1;
644  break;
645  case 'u':
646  break; /* disable this feature */
647  config->username = optarg;
648  /* Parse the username into uid and gid */
649  config->gid = getgid();
650  config->uid = getuid();
651  if (*config->username) {
652  struct passwd *pwd;
653  if (isdigit(*config->username)) {
654  char *t;
655  config->uid = strtol(config->username, &t, 10);
656  if (*t != 0) {
657  if (*t != '.' || !isdigit(*++t)) {
658  log_msg(config, LOG_ERR, "-u user or -u uid or -u uid.gid. exiting...");
659  exit(1);
660  }
661  config->gid = strtol(t, &t, 10);
662  } else {
663  /* Lookup the group id in /etc/passwd */
664  if ((pwd = getpwuid(config->uid)) == NULL) {
665  log_msg(config, LOG_ERR, "user id %u does not exist. exiting...", (unsigned) config->uid);
666  exit(1);
667  } else {
668  config->gid = pwd->pw_gid;
669  }
670  endpwent();
671  }
672  } else {
673  /* Lookup the user id in /etc/passwd */
674  if ((pwd = getpwnam(config->username)) == NULL) {
675  log_msg(config, LOG_ERR, "user '%s' does not exist. exiting...", config->username);
676  exit(1);
677  } else {
678  config->uid = pwd->pw_uid;
679  config->gid = pwd->pw_gid;
680  }
681  endpwent();
682  }
683  }
684  break;
685  case 'p':
686  config->policy = optarg;
687  config->once = true;
688  fprintf(stdout, "Will only process policy \"%s\", will only run once. Check the logs for results. \n", config->policy);
689  break;
690  case 'h':
691  usage(config->program);
692  exit(0);
693  case '?':
694  usage(config->program);
695  exit(0);
696  case 'V':
697  version();
698  exit(0);
699  default:
700  usage(config->program);
701  exit(0);
702  }
703  }
704 }
705 
706 /*
707  * Returns 0 if the the config file could be read and non-zero if it could not.
708  *
709  * Any function calling this should exit on a non-zero return.
710  */
711 int
713 {
714  xmlDocPtr doc = NULL;
715  xmlDocPtr rngdoc = NULL;
716  xmlXPathContextPtr xpathCtx = NULL;
717  xmlXPathObjectPtr xpathObj = NULL;
718  xmlRelaxNGParserCtxtPtr rngpctx = NULL;
719  xmlRelaxNGValidCtxtPtr rngctx = NULL;
720  xmlRelaxNGPtr schema = NULL;
721  xmlChar *iv_expr = (unsigned char*) "//Configuration/Enforcer/Interval";
722  xmlChar *mk_expr = (unsigned char*) "//Configuration/Enforcer/ManualKeyGeneration";
723  xmlChar *rn_expr = (unsigned char*) "//Configuration/Enforcer/RolloverNotification";
724  xmlChar *ds_expr = (unsigned char*) "//Configuration/Enforcer/DelegationSignerSubmitCommand";
725  xmlChar *pid_expr = (unsigned char*) "//Configuration/Enforcer/PidFile";
726  xmlChar *litexpr = (unsigned char*) "//Configuration/Enforcer/Datastore/SQLite";
727  xmlChar *mysql_host = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host";
728  xmlChar *mysql_port = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host/@port";
729  xmlChar *mysql_db = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Database";
730  xmlChar *mysql_user = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Username";
731  xmlChar *mysql_pass = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Password";
732  xmlChar *log_user_expr = (unsigned char*) "//Configuration/Common/Logging/Syslog/Facility";
733 
734  int mysec = 0;
735  char *logFacilityName;
736  int my_log_user = DEFAULT_LOG_FACILITY;
737  int status;
738  int db_found = 0;
739  char* filename = NULL;
740  char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
741 
742  char* temp_char = NULL;
743  char* str = NULL; /* used to split DSSub command */
744 
745  FILE *file;
746 
747  /* Change the config file location if one was provided on the command line */
748  if (config->configfile != NULL) {
749  filename = StrStrdup(config->configfile);
750  } else {
751  filename = StrStrdup(OPENDNSSEC_CONFIG_FILE);
752  }
753 
754  if (verbose) {
755  log_msg(config, LOG_INFO, "Reading config \"%s\"", filename);
756  }
757 
758  /* Load XML document */
759  doc = xmlParseFile(filename);
760  if (doc == NULL) {
761  /* To get a better error message try to open the file */
762  file = fopen(filename, "r");
763  if (file == NULL) {
764  log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", filename);
765  } else {
766  log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", filename);
767  fclose(file);
768  }
769  return(-1);
770  }
771 
772  /* Load rng document */
773  if (verbose) {
774  log_msg(config, LOG_INFO, "Reading config schema \"%s\"", rngfilename);
775  }
776  rngdoc = xmlParseFile(rngfilename);
777  if (rngdoc == NULL) {
778  /* To get a better error message try to open the file */
779  file = fopen(rngfilename, "r");
780  if (file == NULL) {
781  log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", rngfilename);
782  } else {
783  log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", rngfilename);
784  fclose(file);
785  }
786  return(-1);
787  }
788 
789  /* Create an XML RelaxNGs parser context for the relax-ng document. */
790  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
791  if (rngpctx == NULL) {
792  log_msg(config, LOG_ERR, "Error: unable to create XML RelaxNGs parser context");
793  return(-1);
794  }
795 
796  /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
797  schema = xmlRelaxNGParse(rngpctx);
798  if (schema == NULL) {
799  log_msg(config, LOG_ERR, "Error: unable to parse a schema definition resource");
800  return(-1);
801  }
802 
803  /* Create an XML RelaxNGs validation context based on the given schema */
804  rngctx = xmlRelaxNGNewValidCtxt(schema);
805  if (rngctx == NULL) {
806  log_msg(config, LOG_ERR, "Error: unable to create RelaxNGs validation context based on the schema");
807  return(-1);
808  }
809 
810  xmlRelaxNGSetValidErrors(rngctx,
811  (xmlRelaxNGValidityErrorFunc) log_xml_error,
812  (xmlRelaxNGValidityWarningFunc) log_xml_warn,
813  NULL);
814 
815  /* Validate a document tree in memory. */
816  status = xmlRelaxNGValidateDoc(rngctx,doc);
817  if (status != 0) {
818  log_msg(config, LOG_ERR, "Error validating file \"%s\"", filename);
819  return(-1);
820  }
821  xmlRelaxNGFreeValidCtxt(rngctx);
822  xmlRelaxNGFree(schema);
823  xmlRelaxNGFreeParserCtxt(rngpctx);
824  xmlFreeDoc(rngdoc);
825 
826  /* Now parse a value out of the conf */
827  /* Create xpath evaluation context */
828  xpathCtx = xmlXPathNewContext(doc);
829  if(xpathCtx == NULL) {
830  log_msg(config, LOG_ERR,"Error: unable to create new XPath context");
831  xmlFreeDoc(doc);
832  return(-1);
833  }
834 
835  /* Evaluate xpath expression for interval */
836  xpathObj = xmlXPathEvalExpression(iv_expr, xpathCtx);
837  if(xpathObj == NULL) {
838  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", iv_expr);
839  xmlXPathFreeContext(xpathCtx);
840  xmlFreeDoc(doc);
841  return(-1);
842  }
843 
844  temp_char = (char *)xmlXPathCastToString(xpathObj);
845  status = DtXMLIntervalSeconds(temp_char, &mysec);
846  if (status > 0) {
847  log_msg(config, LOG_ERR, "Error: unable to convert Interval %s to seconds, error: %i", temp_char, status);
848  StrFree(temp_char);
849  return status;
850  }
851  else if (status == -1) {
852  log_msg(config, LOG_INFO, "Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days", temp_char);
853  }
854  config->interval = mysec;
855  if (verbose) {
856  log_msg(config, LOG_INFO, "Communication Interval: %i", config->interval);
857  }
858  StrFree(temp_char);
859  xmlXPathFreeObject(xpathObj);
860 
861  /* Evaluate xpath expression for Manual key generation */
862  xpathObj = xmlXPathEvalExpression(mk_expr, xpathCtx);
863  if(xpathObj == NULL) {
864  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mk_expr);
865  xmlXPathFreeContext(xpathCtx);
866  xmlFreeDoc(doc);
867  return(-1);
868  }
869 
870  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
871  /* Manual key generation tag is present */
872  config->manualKeyGeneration = 1;
873  }
874  else {
875  /* Tag absent */
876  config->manualKeyGeneration = 0;
877  }
878  xmlXPathFreeObject(xpathObj);
879 
880  /* Evaluate xpath expression for rollover notification interval */
881  xpathObj = xmlXPathEvalExpression(rn_expr, xpathCtx);
882  if(xpathObj == NULL) {
883  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", rn_expr);
884  xmlXPathFreeContext(xpathCtx);
885  xmlFreeDoc(doc);
886  return(-1);
887  }
888 
889  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
890  /* Tag RolloverNotification is present; set rolloverNotify */
891  temp_char = (char *)xmlXPathCastToString(xpathObj);
892  status = DtXMLIntervalSeconds(temp_char, &mysec);
893  if (status > 0) {
894  log_msg(config, LOG_ERR, "Error: unable to convert RolloverNotification %s to seconds, error: %i", temp_char, status);
895  StrFree(temp_char);
896  xmlXPathFreeObject(xpathObj);
897  return status;
898  }
899  else if (status == -1) {
900  log_msg(config, LOG_INFO, "Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days", temp_char);
901  }
902  config->rolloverNotify = mysec;
903  if (verbose) {
904  log_msg(config, LOG_INFO, "Rollover Notification Interval: %i", config->rolloverNotify);
905  }
906  StrFree(temp_char);
907  }
908  else {
909  /* Tag RolloverNotification absent, set rolloverNotify to -1 */
910  config->rolloverNotify = -1;
911  }
912  xmlXPathFreeObject(xpathObj);
913 
914  /* Evaluate xpath expression for DelegationSignerSubmitCommand */
915  xpathObj = xmlXPathEvalExpression(ds_expr, xpathCtx);
916  if(xpathObj == NULL) {
917  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", ds_expr);
918  xmlXPathFreeContext(xpathCtx);
919  xmlFreeDoc(doc);
920  return(-1);
921  }
922  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
923  /* Tag DelegationSignerSubmitCommand is present; set DSSubmitCmd */
924  if (config->DSSubmitCmd != NULL) {
925  StrFree(config->DSSubmitCmd);
926  }
927  config->DSSubmitCmd = (char *)xmlXPathCastToString(xpathObj);
928 
929  /* If the string ends " --cka_id" strip that off and set flag */
930  str = strstr(config->DSSubmitCmd, " --cka_id");
931  if (str) {
932  config->DSSubCKA_ID = 1;
933  *str = 0;
934  } else {
935  config->DSSubCKA_ID = 0;
936  }
937 
938  if (verbose) {
939  log_msg(config, LOG_INFO, "Using command: %s to submit DS records", config->DSSubmitCmd);
940  }
941  } else {
942  if (verbose) {
943  log_msg(config, LOG_INFO, "No DS Submit command supplied");
944  }
945  config->DSSubmitCmd[0] = '\0';
946  }
947  xmlXPathFreeObject(xpathObj);
948 
949  /* Evaluate xpath expression for SQLite file location */
950 
951  xpathObj = xmlXPathEvalExpression(litexpr, xpathCtx);
952  if(xpathObj == NULL) {
953  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", litexpr);
954  xmlXPathFreeContext(xpathCtx);
955  xmlFreeDoc(doc);
956  return(-1);
957  }
958  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
959  db_found = SQLITE_DB;
960  if (config->schema != NULL) {
961  StrFree(config->schema);
962  }
963  config->schema = xmlXPathCastToString(xpathObj);
964  if (verbose) {
965  log_msg(config, LOG_INFO, "SQLite database set to: %s", config->schema);
966  }
967  }
968  xmlXPathFreeObject(xpathObj);
969 
970  if (db_found == 0) {
971  db_found = MYSQL_DB;
972 
973  /* Get all of the MySQL stuff read in too */
974  /* HOST */
975  xpathObj = xmlXPathEvalExpression(mysql_host, xpathCtx);
976  if(xpathObj == NULL) {
977  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_host);
978  xmlXPathFreeContext(xpathCtx);
979  xmlFreeDoc(doc);
980  return(-1);
981  }
982  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
983  if (config->host != NULL) {
984  StrFree(config->host);
985  }
986  config->host = xmlXPathCastToString(xpathObj);
987  if (verbose) {
988  log_msg(config, LOG_INFO, "MySQL database host set to: %s", config->host);
989  }
990  }
991  xmlXPathFreeObject(xpathObj);
992 
993  /* PORT */
994  xpathObj = xmlXPathEvalExpression(mysql_port, xpathCtx);
995  if(xpathObj == NULL) {
996  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_port);
997  xmlXPathFreeContext(xpathCtx);
998  xmlFreeDoc(doc);
999  return(-1);
1000  }
1001  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
1002  if (config->port != NULL) {
1003  StrFree(config->port);
1004  }
1005  config->port = xmlXPathCastToString(xpathObj);
1006  if (verbose) {
1007  log_msg(config, LOG_INFO, "MySQL database port set to: %s", config->port);
1008  }
1009  }
1010  xmlXPathFreeObject(xpathObj);
1011 
1012  /* SCHEMA */
1013  xpathObj = xmlXPathEvalExpression(mysql_db, xpathCtx);
1014  if(xpathObj == NULL) {
1015  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_db);
1016  xmlXPathFreeContext(xpathCtx);
1017  xmlFreeDoc(doc);
1018  return(-1);
1019  }
1020  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
1021  if (config->schema != NULL) {
1022  StrFree(config->schema);
1023  }
1024  config->schema = xmlXPathCastToString(xpathObj);
1025  if (verbose) {
1026  log_msg(config, LOG_INFO, "MySQL database schema set to: %s", config->schema);
1027  }
1028  } else {
1029  db_found = 0;
1030  }
1031  xmlXPathFreeObject(xpathObj);
1032 
1033  /* DB USER */
1034  xpathObj = xmlXPathEvalExpression(mysql_user, xpathCtx);
1035  if(xpathObj == NULL) {
1036  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_user);
1037  xmlXPathFreeContext(xpathCtx);
1038  xmlFreeDoc(doc);
1039  return(-1);
1040  }
1041  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
1042  if (config->user != NULL) {
1043  StrFree(config->user);
1044  }
1045  config->user = xmlXPathCastToString(xpathObj);
1046  if (verbose) {
1047  log_msg(config, LOG_INFO, "MySQL database user set to: %s", config->user);
1048  }
1049  } else {
1050  db_found = 0;
1051  }
1052  xmlXPathFreeObject(xpathObj);
1053 
1054  /* DB PASSWORD */
1055  xpathObj = xmlXPathEvalExpression(mysql_pass, xpathCtx);
1056  if(xpathObj == NULL) {
1057  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_pass);
1058  xmlXPathFreeContext(xpathCtx);
1059  xmlFreeDoc(doc);
1060  return(-1);
1061  }
1062  /* password may be blank */
1063 
1064  if (config->password != NULL) {
1065  StrFree(config->password);
1066  }
1067  config->password = xmlXPathCastToString(xpathObj);
1068  if (verbose) {
1069  log_msg(config, LOG_INFO, "MySQL database password set");
1070  }
1071  xmlXPathFreeObject(xpathObj);
1072 
1073  }
1074 
1075  /* Check that we found one or the other database */
1076  if(db_found == 0) {
1077  log_msg(config, LOG_ERR, "Error: unable to find complete database connection expression in %s", filename);
1078  xmlFreeDoc(doc);
1079  return(-1);
1080  }
1081 
1082  /* Check that we found the right database type */
1083  if (db_found != DbFlavour()) {
1084  log_msg(config, LOG_ERR, "Error: Config file %s specifies database type %s but system is compiled to use %s", filename, (db_found==1) ? "MySQL" : "sqlite3", (db_found==2) ? "MySQL" : "sqlite3");
1085  xmlFreeDoc(doc);
1086  return(-1);
1087  }
1088 
1089  /* Evaluate xpath expression for log facility (user) */
1090  xpathObj = xmlXPathEvalExpression(log_user_expr, xpathCtx);
1091  if(xpathObj == NULL) {
1092  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", log_user_expr);
1093  xmlXPathFreeContext(xpathCtx);
1094  xmlFreeDoc(doc);
1095  return(-1);
1096  }
1097 
1098  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
1099  /* tag present */
1100  logFacilityName = (char *)xmlXPathCastToString(xpathObj);
1101 
1102  status = get_log_user(logFacilityName, &my_log_user);
1103  if (status > 0) {
1104  log_msg(config, LOG_ERR, "Error: unable to set log user: %s, error: %i", logFacilityName, status);
1105  StrFree(logFacilityName);
1106  xmlXPathFreeObject(xpathObj);
1107  xmlXPathFreeContext(xpathCtx);
1108  xmlFreeDoc(doc);
1109  return status;
1110  }
1111  config->log_user = my_log_user;
1112  if (verbose) {
1113  log_msg(config, LOG_INFO, "Log User set to: %s", logFacilityName);
1114  }
1115 
1116  } else {
1117  /* tag _not_ present, use default */
1118  logFacilityName = StrStrdup( (char *)DEFAULT_LOG_FACILITY_STRING );
1119  config->log_user = DEFAULT_LOG_FACILITY;
1120  if (verbose) {
1121  log_msg(config, LOG_INFO, "Using default log user: %s", logFacilityName);
1122  }
1123  }
1124 
1125  /* Evaluate xpath expression for pidfile */
1126  xpathObj = xmlXPathEvalExpression(pid_expr, xpathCtx);
1127  if(xpathObj == NULL) {
1128  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", pid_expr);
1129  xmlXPathFreeContext(xpathCtx);
1130  xmlFreeDoc(doc);
1131  return(-1);
1132  }
1133 
1134  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
1135  /* tag present */
1136  if (!config->pidfile_set) {
1137  config->pidfile = (char *)xmlXPathCastToString(xpathObj);
1138  if (verbose) {
1139  log_msg(config, LOG_INFO, "Pidfile set to: %s", config->pidfile);
1140  }
1141  }
1142  }
1143 
1144  xmlXPathFreeObject(xpathObj);
1145 
1146  log_switch(my_log_user, logFacilityName, config->program, verbose);
1147 
1148  /* Cleanup */
1149  /* TODO: some other frees are needed */
1150  xmlFreeDoc(doc);
1151  StrFree(logFacilityName);
1152  StrFree(filename);
1153 
1154  return(0);
1155 
1156 }
1157 
1158 /* To overcome the potential differences in sqlite compile flags assume that it is not
1159  happy with multiple connections.
1160 
1161  The following 2 functions take out a lock and release it
1162 */
1163 
1164 int get_lite_lock(char *lock_filename, FILE* lock_fd)
1165 {
1166  struct flock fl;
1167  struct timeval tv;
1168 
1169  if (lock_fd == NULL) {
1170  log_msg(NULL, LOG_ERR, "%s could not be opened", lock_filename);
1171  return 1;
1172  }
1173 
1174  memset(&fl, 0, sizeof(struct flock));
1175  fl.l_type = F_WRLCK;
1176  fl.l_whence = SEEK_SET;
1177  fl.l_pid = getpid();
1178 
1179  while (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
1180  if (errno == EACCES || errno == EAGAIN) {
1181  log_msg(NULL, LOG_INFO, "%s already locked, sleep", lock_filename);
1182 
1183  /* sleep for 10 seconds TODO make this configurable? */
1184  tv.tv_sec = 10;
1185  tv.tv_usec = 0;
1186  select(0, NULL, NULL, NULL, &tv);
1187 
1188  } else {
1189  log_msg(NULL, LOG_INFO, "couldn't get lock on %s, %s", lock_filename, strerror(errno));
1190  return 1;
1191  }
1192  }
1193 
1194  return 0;
1195 
1196 }
1197 
1198 int release_lite_lock(FILE* lock_fd)
1199 {
1200  struct flock fl;
1201 
1202  if (lock_fd == NULL) {
1203  return 1;
1204  }
1205 
1206  memset(&fl, 0, sizeof(struct flock));
1207  fl.l_type = F_UNLCK;
1208  fl.l_whence = SEEK_SET;
1209 
1210  if (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
1211  return 1;
1212  }
1213 
1214  return 0;
1215 }
1216 
1217 /* convert the name of a log facility (user) into a number */
1218 int get_log_user(const char* username, int* usernumber)
1219 {
1220  char* case_username = NULL;
1221 
1222  if (username == NULL) {
1223  return 1;
1224  }
1225  /* Start with our default */
1226  *usernumber = DEFAULT_LOG_FACILITY;
1227 
1228  case_username = StrStrdup(username);
1229  (void) StrToUpper(case_username);
1230 
1231  /* POSIX only specifies LOG_USER and LOG_LOCAL[0 .. 7] */
1232  if (strncmp(case_username, "USER", 4) == 0) {
1233  *usernumber = LOG_USER;
1234  }
1235 #ifdef LOG_KERN
1236  else if (strncmp(case_username, "KERN", 4) == 0) {
1237  *usernumber = LOG_KERN;
1238  }
1239 #endif /* LOG_KERN */
1240 #ifdef LOG_MAIL
1241  else if (strncmp(case_username, "MAIL", 4) == 0) {
1242  *usernumber = LOG_MAIL;
1243  }
1244 #endif /* LOG_MAIL */
1245 #ifdef LOG_DAEMON
1246  else if (strncmp(case_username, "DAEMON", 6) == 0) {
1247  *usernumber = LOG_DAEMON;
1248  }
1249 #endif /* LOG_DAEMON */
1250 #ifdef LOG_AUTH
1251  else if (strncmp(case_username, "AUTH", 4) == 0) {
1252  *usernumber = LOG_AUTH;
1253  }
1254 #endif /* LOG_AUTH */
1255 #ifdef LOG_SYSLOG
1256  else if (strncmp(case_username, "SYSLOG", 6) == 0) {
1257  *usernumber = LOG_SYSLOG;
1258  }
1259 #endif /* LOG_SYSLOG */
1260 #ifdef LOG_LPR
1261  else if (strncmp(case_username, "LPR", 3) == 0) {
1262  *usernumber = LOG_LPR;
1263  }
1264 #endif /* LOG_LPR */
1265 #ifdef LOG_NEWS
1266  else if (strncmp(case_username, "NEWS", 4) == 0) {
1267  *usernumber = LOG_NEWS;
1268  }
1269 #endif /* LOG_NEWS */
1270 #ifdef LOG_UUCP
1271  else if (strncmp(case_username, "UUCP", 4) == 0) {
1272  *usernumber = LOG_UUCP;
1273  }
1274 #endif /* LOG_UUCP */
1275 #ifdef LOG_AUDIT /* Ubuntu at least doesn't want us to use LOG_AUDIT */
1276  else if (strncmp(case_username, "AUDIT", 5) == 0) {
1277  *usernumber = LOG_AUDIT;
1278  }
1279 #endif /* LOG_AUDIT */
1280 #ifdef LOG_CRON
1281  else if (strncmp(case_username, "CRON", 4) == 0) {
1282  *usernumber = LOG_CRON;
1283  }
1284 #endif /* LOG_CRON */
1285  else if (strncmp(case_username, "LOCAL0", 6) == 0) {
1286  *usernumber = LOG_LOCAL0;
1287  }
1288  else if (strncmp(case_username, "LOCAL1", 6) == 0) {
1289  *usernumber = LOG_LOCAL1;
1290  }
1291  else if (strncmp(case_username, "LOCAL2", 6) == 0) {
1292  *usernumber = LOG_LOCAL2;
1293  }
1294  else if (strncmp(case_username, "LOCAL3", 6) == 0) {
1295  *usernumber = LOG_LOCAL3;
1296  }
1297  else if (strncmp(case_username, "LOCAL4", 6) == 0) {
1298  *usernumber = LOG_LOCAL4;
1299  }
1300  else if (strncmp(case_username, "LOCAL5", 6) == 0) {
1301  *usernumber = LOG_LOCAL5;
1302  }
1303  else if (strncmp(case_username, "LOCAL6", 6) == 0) {
1304  *usernumber = LOG_LOCAL6;
1305  }
1306  else if (strncmp(case_username, "LOCAL7", 6) == 0) {
1307  *usernumber = LOG_LOCAL7;
1308  }
1309 
1310  StrFree(case_username);
1311 
1312  return 0;
1313 
1314 }
1315 
unsigned char * password
Definition: daemon.h:106
unsigned char * schema
Definition: daemon.h:107
bool once
Definition: daemon.h:89
#define DEFAULT_LOG_FACILITY
Definition: daemon.h:79
pid_t pid
Definition: daemon.h:90
#define StrFree(x)
Definition: string_util.h:66
int make_directory(DAEMONCONFIG *config, const char *path)
Definition: daemon_util.c:578
char * pidfile
Definition: daemon.h:91
char * DSSubmitCmd
Definition: daemon.h:114
int DbFlavour(void)
char * optarg
int daemon_our_pidfile
Definition: daemon.c:98
int log_user
Definition: daemon.h:118
#define DEFAULT_LOG_FACILITY_STRING
Definition: daemon.h:80
const char * program
Definition: daemon.h:87
uint16_t interval
Definition: daemon.h:109
char * username
Definition: daemon.h:94
int getPermsForDrop(DAEMONCONFIG *config)
Definition: daemon_util.c:91
#define COPYRIGHT_STR
Definition: daemon.h:126
uid_t uid
Definition: daemon.h:92
void log_xml_error(void *ignore, const char *format,...)
Definition: daemon_util.c:354
int rolloverNotify
Definition: daemon.h:113
void cmdlParse(DAEMONCONFIG *config, int *argc, char **argv)
Definition: daemon_util.c:623
int get_log_user(const char *username, int *usernumber)
Definition: daemon_util.c:1218
void log_init(int facility, const char *program_name)
Definition: daemon_util.c:265
char * configfile
Definition: daemon.h:103
char * StrStrdup(const char *string)
Definition: string_util.c:124
#define AUTHOR_NAME
Definition: daemon.h:125
unsigned char * host
Definition: daemon.h:105
int pidfile_set
Definition: daemon.h:119
int manualKeyGeneration
Definition: daemon.h:112
#define SQLITE_DB
Definition: database.h:46
int ReadConfig(DAEMONCONFIG *config, int verbose)
Definition: daemon_util.c:712
int write_data(DAEMONCONFIG *config, FILE *file, const void *data, size_t size)
Definition: daemon_util.c:416
int release_lite_lock(FILE *lock_fd)
Definition: daemon_util.c:1198
void ksm_log_msg(const char *format)
Definition: daemon_util.c:313
bool debug
Definition: daemon.h:88
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:76
void log_xml_warn(void *ignore, const char *format,...)
Definition: daemon_util.c:372
int createPidDir(DAEMONCONFIG *config)
Definition: daemon_util.c:536
#define MYSQL_DB
Definition: database.h:45
int verbose
Definition: kaspcheck.c:49
char * policy
Definition: daemon.h:116
gid_t gid
Definition: daemon.h:93
int get_lite_lock(char *lock_filename, FILE *lock_fd)
Definition: daemon_util.c:1164
DAEMONCONFIG config
Definition: daemon.c:71
int writepid(DAEMONCONFIG *config)
Definition: daemon_util.c:467
char * groupname
Definition: daemon.h:95
void log_msg(DAEMONCONFIG *config, int priority, const char *format,...)
Definition: daemon_util.c:294
int DtXMLIntervalSeconds(const char *text, int *interval)
Definition: datetime.c:925
size_t StrToUpper(char *text)
Definition: string_util.c:353
unsigned char * port
Definition: daemon.h:108
unsigned char * user
Definition: daemon.h:104
void log_switch(int facility, const char *facility_name, const char *program_name, int verbose)
Definition: daemon_util.c:275
int DSSubCKA_ID
Definition: daemon.h:115