OpenDNSSEC-enforcer
1.3.4
|
00001 /* 00002 * $Id: daemon_util.c 4253 2010-12-06 12:15:39Z matthijs $ 00003 * 00004 * Copyright (c) 2008-2009 Nominet UK. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00029 /* 00030 * daemon_util.c code needed to get a daemon up and running 00031 * 00032 * edit the DAEMONCONFIG and cmlParse function 00033 * in daemon_util.[c|h] to add options specific 00034 * to your app 00035 * 00036 * gcc -o daemon daemon_util.c daemon.c 00037 * 00038 * Most of this is based on stuff I have seen in NSD 00039 */ 00040 #include "config.h" 00041 00042 #ifndef _GNU_SOURCE 00043 #define _GNU_SOURCE 00044 #endif 00045 #include <stdlib.h> 00046 #include <stdio.h> 00047 #include <unistd.h> 00048 #include <string.h> 00049 #include <syslog.h> 00050 #include <stdarg.h> 00051 #include <errno.h> 00052 #include <pwd.h> 00053 #include <grp.h> 00054 #include <ctype.h> 00055 #include <signal.h> 00056 #include <fcntl.h> 00057 #include <syslog.h> 00058 00059 #include <sys/select.h> 00060 #include <sys/types.h> 00061 #include <sys/stat.h> 00062 00063 #include <libxml/tree.h> 00064 #include <libxml/parser.h> 00065 #include <libxml/xpath.h> 00066 #include <libxml/xpathInternals.h> 00067 #include <libxml/relaxng.h> 00068 00069 #include "daemon.h" 00070 #include "daemon_util.h" 00071 00072 #include "ksm/database.h" 00073 #include "ksm/datetime.h" 00074 #include "ksm/string_util.h" 00075 #include "ksm/string_util2.h" 00076 00077 int 00078 getPermsForDrop(DAEMONCONFIG* config) 00079 { 00080 int status = 0; 00081 00082 xmlDocPtr doc = NULL; 00083 xmlDocPtr rngdoc = NULL; 00084 xmlXPathContextPtr xpathCtx = NULL; 00085 xmlXPathObjectPtr xpathObj = NULL; 00086 xmlRelaxNGParserCtxtPtr rngpctx = NULL; 00087 xmlRelaxNGValidCtxtPtr rngctx = NULL; 00088 xmlRelaxNGPtr schema = NULL; 00089 xmlChar *user_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/User"; 00090 xmlChar *group_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/Group"; 00091 00092 char* filename = NULL; 00093 char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng"; 00094 char* temp_char = NULL; 00095 00096 struct passwd *pwd; 00097 struct group *grp; 00098 00099 FILE *file; 00100 00101 if (config->configfile != NULL) { 00102 filename = StrStrdup(config->configfile); 00103 } else { 00104 filename = StrStrdup(OPENDNSSEC_CONFIG_FILE); 00105 } 00106 00107 /* Load XML document */ 00108 doc = xmlParseFile(filename); 00109 if (doc == NULL) { 00110 /* To get a better error message try to open the file */ 00111 file = fopen(filename, "r"); 00112 if (file == NULL) { 00113 log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", filename); 00114 } else { 00115 log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", filename); 00116 fclose(file); 00117 } 00118 return(-1); 00119 } 00120 00121 /* Load rng document */ 00122 rngdoc = xmlParseFile(rngfilename); 00123 if (rngdoc == NULL) { 00124 /* To get a better error message try to open the file */ 00125 file = fopen(rngfilename, "r"); 00126 if (file == NULL) { 00127 log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", rngfilename); 00128 } else { 00129 log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", rngfilename); 00130 fclose(file); 00131 } 00132 return(-1); 00133 } 00134 00135 /* Create an XML RelaxNGs parser context for the relax-ng document. */ 00136 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc); 00137 if (rngpctx == NULL) { 00138 log_msg(config, LOG_ERR, "Error: unable to create XML RelaxNGs parser context"); 00139 return(-1); 00140 } 00141 00142 /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */ 00143 schema = xmlRelaxNGParse(rngpctx); 00144 if (schema == NULL) { 00145 log_msg(config, LOG_ERR, "Error: unable to parse a schema definition resource"); 00146 return(-1); 00147 } 00148 00149 /* Create an XML RelaxNGs validation context based on the given schema */ 00150 rngctx = xmlRelaxNGNewValidCtxt(schema); 00151 if (rngctx == NULL) { 00152 log_msg(config, LOG_ERR, "Error: unable to create RelaxNGs validation context based on the schema"); 00153 return(-1); 00154 } 00155 00156 xmlRelaxNGSetValidErrors(rngctx, 00157 (xmlRelaxNGValidityErrorFunc) log_xml_error, 00158 (xmlRelaxNGValidityWarningFunc) log_xml_warn, 00159 NULL); 00160 00161 /* Validate a document tree in memory. */ 00162 status = xmlRelaxNGValidateDoc(rngctx,doc); 00163 if (status != 0) { 00164 log_msg(config, LOG_ERR, "Error validating file \"%s\"", filename); 00165 return(-1); 00166 } 00167 00168 /* Now parse a value out of the conf */ 00169 /* Create xpath evaluation context */ 00170 xpathCtx = xmlXPathNewContext(doc); 00171 if(xpathCtx == NULL) { 00172 log_msg(config, LOG_ERR,"Error: unable to create new XPath context"); 00173 xmlFreeDoc(doc); 00174 return(-1); 00175 } 00176 00177 /* Set the group if specified */ 00178 xpathObj = xmlXPathEvalExpression(group_expr, xpathCtx); 00179 if(xpathObj == NULL) { 00180 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", group_expr); 00181 xmlXPathFreeContext(xpathCtx); 00182 xmlFreeDoc(doc); 00183 return(-1); 00184 } 00185 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00186 temp_char = (char*) xmlXPathCastToString(xpathObj); 00187 StrAppend(&config->groupname, temp_char); 00188 StrFree(temp_char); 00189 xmlXPathFreeObject(xpathObj); 00190 } else { 00191 config->groupname = NULL; 00192 } 00193 00194 /* Set the user to drop to if specified */ 00195 xpathObj = xmlXPathEvalExpression(user_expr, xpathCtx); 00196 if(xpathObj == NULL) { 00197 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", user_expr); 00198 xmlXPathFreeContext(xpathCtx); 00199 xmlFreeDoc(doc); 00200 return(-1); 00201 } 00202 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00203 temp_char = (char*) xmlXPathCastToString(xpathObj); 00204 StrAppend(&config->username, temp_char); 00205 StrFree(temp_char); 00206 xmlXPathFreeObject(xpathObj); 00207 } else { 00208 config->username = NULL; 00209 } 00210 00211 /* Set uid and gid if required */ 00212 if (config->username != NULL) { 00213 /* Lookup the user id in /etc/passwd */ 00214 if ((pwd = getpwnam(config->username)) == NULL) { 00215 syslog(LOG_ERR, "user '%s' does not exist. exiting...\n", config->username); 00216 exit(1); 00217 } else { 00218 config->uid = pwd->pw_uid; 00219 } 00220 endpwent(); 00221 } 00222 if (config->groupname) { 00223 /* Lookup the group id in /etc/groups */ 00224 if ((grp = getgrnam(config->groupname)) == NULL) { 00225 syslog(LOG_ERR, "group '%s' does not exist. exiting...\n", config->groupname); 00226 exit(1); 00227 } else { 00228 config->gid = grp->gr_gid; 00229 } 00230 endgrent(); 00231 } 00232 00233 xmlXPathFreeContext(xpathCtx); 00234 xmlRelaxNGFree(schema); 00235 xmlRelaxNGFreeValidCtxt(rngctx); 00236 xmlRelaxNGFreeParserCtxt(rngpctx); 00237 xmlFreeDoc(doc); 00238 xmlFreeDoc(rngdoc); 00239 StrFree(filename); 00240 00241 return 0; 00242 } 00243 00244 /* Set up logging as per default (facility may be switched based on config file) */ 00245 void log_init(int facility, const char *program_name) 00246 { 00247 openlog(program_name, 0, facility); 00248 } 00249 00250 /* Switch log to new facility */ 00251 void log_switch(int facility, const char *facility_name, const char *program_name, int verbose) 00252 { 00253 closelog(); 00254 openlog(program_name, 0, facility); 00255 if (verbose) { 00256 log_msg(NULL, LOG_INFO, "Switched log facility to: %s", facility_name); 00257 } 00258 } 00259 00260 00261 void 00262 log_msg(DAEMONCONFIG *config, int priority, const char *format, ...) 00263 { 00264 /* If the variable arg list is bad then random errors can occur */ 00265 va_list args; 00266 if (config && config->debug) priority = LOG_ERR; 00267 va_start(args, format); 00268 vsyslog(priority, format, args); 00269 va_end(args); 00270 } 00271 00272 /* 00273 * log function suitable for libksm callback 00274 */ 00275 void 00276 ksm_log_msg(const char *format) 00277 { 00278 if (strncmp(format, "ERROR:", 6) == 0) { 00279 syslog(LOG_ERR, "%s", format); 00280 } 00281 else if (strncmp(format, "INFO:", 5) == 0) { 00282 syslog(LOG_INFO, "%s", format); 00283 } 00284 else if (strncmp(format, "WARNING:", 8) == 0) { 00285 syslog(LOG_WARNING, "%s", format); 00286 } 00287 else if (strncmp(format, "DEBUG:", 6) == 0) { 00288 syslog(LOG_DEBUG, "%s", format); 00289 } 00290 else { 00291 syslog(LOG_ERR, "%s", format); 00292 } 00293 } 00294 00295 /* XML Error Message */ 00296 void 00297 log_xml_error(void *ignore, const char *format, ...) 00298 { 00299 va_list args; 00300 00301 (void) ignore; 00302 00303 /* If the variable arg list is bad then random errors can occur */ 00304 va_start(args, format); 00305 vsyslog(LOG_ERR, format, args); 00306 va_end(args); 00307 } 00308 00309 /* XML Warning Message */ 00310 void 00311 log_xml_warn(void *ignore, const char *format, ...) 00312 { 00313 va_list args; 00314 00315 (void) ignore; 00316 00317 /* If the variable arg list is bad then random errors can occur */ 00318 va_start(args, format); 00319 vsyslog(LOG_INFO, format, args); 00320 va_end(args); 00321 } 00322 00323 static void 00324 usage(const char* prog) 00325 { 00326 fprintf(stderr, "Usage: %s [OPTION]...\n", prog); 00327 fprintf(stderr, "OpenDNSSEC Enforcer version %s\n\n", VERSION); 00328 fprintf(stderr, "Supported options:\n"); 00329 fprintf(stderr, " -c <file> Use alternate conf.xml.\n"); 00330 fprintf(stderr, " -d Debug.\n"); 00331 fprintf(stderr, " -1 Run once, then exit.\n"); 00332 /* fprintf(stderr, " -u user Change effective uid to the specified user.\n");*/ 00333 fprintf(stderr, " -P pidfile Specify the PID file to write.\n"); 00334 00335 fprintf(stderr, " -V Print version.\n"); 00336 fprintf(stderr, " -[?|h] This help.\n"); 00337 } 00338 00339 static void 00340 version(void) 00341 { 00342 fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); 00343 fprintf(stderr, "Written by %s.\n\n", AUTHOR_NAME); 00344 fprintf(stderr, "%s. This is free software.\n", COPYRIGHT_STR); 00345 fprintf(stderr, "See source files for more license information\n"); 00346 exit(0); 00347 } 00348 00349 int 00350 write_data(DAEMONCONFIG *config, FILE *file, const void *data, size_t size) 00351 { 00352 size_t result; 00353 00354 if (size == 0) 00355 return 1; 00356 00357 result = fwrite(data, 1, size, file); 00358 00359 if (result == 0) { 00360 log_msg(config, LOG_ERR, "write failed: %s", strerror(errno)); 00361 return 0; 00362 } else if (result < size) { 00363 log_msg(config, LOG_ERR, "short write (disk full?)"); 00364 return 0; 00365 } else { 00366 return 1; 00367 } 00368 } 00369 00370 int 00371 writepid (DAEMONCONFIG *config) 00372 { 00373 FILE * fd; 00374 char pidbuf[32]; 00375 00376 snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) config->pid); 00377 00378 if ((fd = fopen(config->pidfile, "w")) == NULL ) { 00379 return -1; 00380 } 00381 00382 if (!write_data(config, fd, pidbuf, strlen(pidbuf))) { 00383 fclose(fd); 00384 return -1; 00385 } 00386 fclose(fd); 00387 00388 if (chown(config->pidfile, config->uid, config->gid) == -1) { 00389 log_msg(config, LOG_ERR, "cannot chown(%u,%u) %s: %s", 00390 (unsigned) config->uid, (unsigned) config->gid, 00391 config->pidfile, strerror(errno)); 00392 return -1; 00393 } 00394 00395 return 0; 00396 } 00397 00398 int 00399 createPidDir (DAEMONCONFIG *config) 00400 { 00401 char* directory = NULL; 00402 char* slash; 00403 struct stat stat_ret; 00404 char *path = getenv("PWD"); 00405 00406 /* Find the directory part of the (fully qualified) pidfile */ 00407 if (*config->pidfile != '/') { 00408 StrAppend(&directory, path); 00409 StrAppend(&directory, "/"); 00410 StrAppend(&directory, config->pidfile); 00411 } else { 00412 directory = StrStrdup(config->pidfile); 00413 } 00414 slash = strrchr(directory, '/'); 00415 *slash = 0; 00416 00417 /* Check that it exists */ 00418 if (stat(directory, &stat_ret) != 0) { 00419 00420 if (errno != ENOENT) { 00421 log_msg(config, LOG_ERR, "cannot stat directory %s: %s", 00422 directory, strerror(errno)); 00423 return -1; 00424 } 00425 } 00426 00427 if (S_ISDIR(stat_ret.st_mode)) { 00428 /* Do nothing, the directory exists already */ 00429 } else { 00430 /* try to create it */ 00431 if (make_directory(config, directory) != 0) { 00432 StrFree(directory); 00433 return -1; 00434 } 00435 } 00436 StrFree(directory); 00437 00438 return 0; 00439 } 00440 00441 int make_directory(DAEMONCONFIG* config, const char* path) { 00442 00443 char* parent; 00444 char* slash; 00445 struct stat stat_ret; 00446 00447 parent = StrStrdup(path); 00448 slash = strrchr(parent, '/'); 00449 00450 *slash = 0; 00451 00452 stat(parent, &stat_ret); 00453 00454 if (!S_ISDIR(stat_ret.st_mode)) { 00455 00456 make_directory(config, parent); 00457 00458 } 00459 00460 StrFree(parent); 00461 00462 if (mkdir(path, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != 0) { 00463 log_msg(NULL, LOG_ERR, "cannot create directory %s: %s\n", 00464 path, strerror(errno)); 00465 return 1; 00466 } 00467 00468 00469 if (chown(path, config->uid, config->gid) == -1) { 00470 log_msg(config, LOG_ERR, "cannot chown(%u,%u) %s: %s", 00471 (unsigned) config->uid, (unsigned) config->gid, 00472 path, strerror(errno)); 00473 return 1; 00474 } 00475 00476 return 0; 00477 00478 } 00479 00480 void 00481 cmdlParse(DAEMONCONFIG* config, int *argc, char **argv) 00482 { 00483 int c; 00484 00485 /* 00486 * Read the command line 00487 */ 00488 while ((c = getopt(*argc, argv, "1c:hdV?u:P:")) != -1) { 00489 switch (c) { 00490 case '1': 00491 config->once = true; 00492 break; 00493 case 'c': 00494 config->configfile = optarg; 00495 break; 00496 case 'd': 00497 config->debug = true; 00498 break; 00499 case 'P': 00500 config->pidfile = optarg; 00501 break; 00502 case 'u': 00503 break; /* disable this feature */ 00504 config->username = optarg; 00505 /* Parse the username into uid and gid */ 00506 config->gid = getgid(); 00507 config->uid = getuid(); 00508 if (*config->username) { 00509 struct passwd *pwd; 00510 if (isdigit(*config->username)) { 00511 char *t; 00512 config->uid = strtol(config->username, &t, 10); 00513 if (*t != 0) { 00514 if (*t != '.' || !isdigit(*++t)) { 00515 log_msg(config, LOG_ERR, "-u user or -u uid or -u uid.gid. exiting..."); 00516 exit(1); 00517 } 00518 config->gid = strtol(t, &t, 10); 00519 } else { 00520 /* Lookup the group id in /etc/passwd */ 00521 if ((pwd = getpwuid(config->uid)) == NULL) { 00522 log_msg(config, LOG_ERR, "user id %u does not exist. exiting...", (unsigned) config->uid); 00523 exit(1); 00524 } else { 00525 config->gid = pwd->pw_gid; 00526 } 00527 endpwent(); 00528 } 00529 } else { 00530 /* Lookup the user id in /etc/passwd */ 00531 if ((pwd = getpwnam(config->username)) == NULL) { 00532 log_msg(config, LOG_ERR, "user '%s' does not exist. exiting...", config->username); 00533 exit(1); 00534 } else { 00535 config->uid = pwd->pw_uid; 00536 config->gid = pwd->pw_gid; 00537 } 00538 endpwent(); 00539 } 00540 } 00541 break; 00542 case 'h': 00543 usage(config->program); 00544 exit(0); 00545 case '?': 00546 usage(config->program); 00547 exit(0); 00548 case 'V': 00549 version(); 00550 exit(0); 00551 default: 00552 usage(config->program); 00553 exit(0); 00554 } 00555 } 00556 } 00557 00558 /* 00559 * Returns 0 if the the config file could be read and non-zero if it could not. 00560 * 00561 * Any function calling this should exit on a non-zero return. 00562 */ 00563 int 00564 ReadConfig(DAEMONCONFIG *config, int verbose) 00565 { 00566 xmlDocPtr doc = NULL; 00567 xmlDocPtr rngdoc = NULL; 00568 xmlXPathContextPtr xpathCtx = NULL; 00569 xmlXPathObjectPtr xpathObj = NULL; 00570 xmlRelaxNGParserCtxtPtr rngpctx = NULL; 00571 xmlRelaxNGValidCtxtPtr rngctx = NULL; 00572 xmlRelaxNGPtr schema = NULL; 00573 xmlChar *iv_expr = (unsigned char*) "//Configuration/Enforcer/Interval"; 00574 xmlChar *mk_expr = (unsigned char*) "//Configuration/Enforcer/ManualKeyGeneration"; 00575 xmlChar *rn_expr = (unsigned char*) "//Configuration/Enforcer/RolloverNotification"; 00576 xmlChar *ds_expr = (unsigned char*) "//Configuration/Enforcer/DelegationSignerSubmitCommand"; 00577 xmlChar *litexpr = (unsigned char*) "//Configuration/Enforcer/Datastore/SQLite"; 00578 xmlChar *mysql_host = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host"; 00579 xmlChar *mysql_port = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host/@port"; 00580 xmlChar *mysql_db = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Database"; 00581 xmlChar *mysql_user = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Username"; 00582 xmlChar *mysql_pass = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Password"; 00583 xmlChar *log_user_expr = (unsigned char*) "//Configuration/Common/Logging/Syslog/Facility"; 00584 00585 int mysec = 0; 00586 char *logFacilityName; 00587 int my_log_user = DEFAULT_LOG_FACILITY; 00588 int status; 00589 int db_found = 0; 00590 char* filename = NULL; 00591 char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng"; 00592 00593 char* temp_char = NULL; 00594 00595 FILE *file; 00596 00597 /* Change the config file location if one was provided on the command line */ 00598 if (config->configfile != NULL) { 00599 filename = StrStrdup(config->configfile); 00600 } else { 00601 filename = StrStrdup(OPENDNSSEC_CONFIG_FILE); 00602 } 00603 00604 if (verbose) { 00605 log_msg(config, LOG_INFO, "Reading config \"%s\"", filename); 00606 } 00607 00608 /* Load XML document */ 00609 doc = xmlParseFile(filename); 00610 if (doc == NULL) { 00611 /* To get a better error message try to open the file */ 00612 file = fopen(filename, "r"); 00613 if (file == NULL) { 00614 log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", filename); 00615 } else { 00616 log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", filename); 00617 fclose(file); 00618 } 00619 return(-1); 00620 } 00621 00622 /* Load rng document */ 00623 if (verbose) { 00624 log_msg(config, LOG_INFO, "Reading config schema \"%s\"", rngfilename); 00625 } 00626 rngdoc = xmlParseFile(rngfilename); 00627 if (rngdoc == NULL) { 00628 /* To get a better error message try to open the file */ 00629 file = fopen(rngfilename, "r"); 00630 if (file == NULL) { 00631 log_msg(config, LOG_ERR, "Error: unable to open file \"%s\"", rngfilename); 00632 } else { 00633 log_msg(config, LOG_ERR, "Error: unable to parse file \"%s\"", rngfilename); 00634 fclose(file); 00635 } 00636 return(-1); 00637 } 00638 00639 /* Create an XML RelaxNGs parser context for the relax-ng document. */ 00640 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc); 00641 if (rngpctx == NULL) { 00642 log_msg(config, LOG_ERR, "Error: unable to create XML RelaxNGs parser context"); 00643 return(-1); 00644 } 00645 00646 /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */ 00647 schema = xmlRelaxNGParse(rngpctx); 00648 if (schema == NULL) { 00649 log_msg(config, LOG_ERR, "Error: unable to parse a schema definition resource"); 00650 return(-1); 00651 } 00652 00653 /* Create an XML RelaxNGs validation context based on the given schema */ 00654 rngctx = xmlRelaxNGNewValidCtxt(schema); 00655 if (rngctx == NULL) { 00656 log_msg(config, LOG_ERR, "Error: unable to create RelaxNGs validation context based on the schema"); 00657 return(-1); 00658 } 00659 00660 xmlRelaxNGSetValidErrors(rngctx, 00661 (xmlRelaxNGValidityErrorFunc) log_xml_error, 00662 (xmlRelaxNGValidityWarningFunc) log_xml_warn, 00663 NULL); 00664 00665 /* Validate a document tree in memory. */ 00666 status = xmlRelaxNGValidateDoc(rngctx,doc); 00667 if (status != 0) { 00668 log_msg(config, LOG_ERR, "Error validating file \"%s\"", filename); 00669 return(-1); 00670 } 00671 xmlRelaxNGFreeValidCtxt(rngctx); 00672 xmlRelaxNGFree(schema); 00673 xmlRelaxNGFreeParserCtxt(rngpctx); 00674 xmlFreeDoc(rngdoc); 00675 00676 /* Now parse a value out of the conf */ 00677 /* Create xpath evaluation context */ 00678 xpathCtx = xmlXPathNewContext(doc); 00679 if(xpathCtx == NULL) { 00680 log_msg(config, LOG_ERR,"Error: unable to create new XPath context"); 00681 xmlFreeDoc(doc); 00682 return(-1); 00683 } 00684 00685 /* Evaluate xpath expression for interval */ 00686 xpathObj = xmlXPathEvalExpression(iv_expr, xpathCtx); 00687 if(xpathObj == NULL) { 00688 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", iv_expr); 00689 xmlXPathFreeContext(xpathCtx); 00690 xmlFreeDoc(doc); 00691 return(-1); 00692 } 00693 00694 temp_char = (char *)xmlXPathCastToString(xpathObj); 00695 status = DtXMLIntervalSeconds(temp_char, &mysec); 00696 if (status > 0) { 00697 log_msg(config, LOG_ERR, "Error: unable to convert Interval %s to seconds, error: %i", temp_char, status); 00698 StrFree(temp_char); 00699 return status; 00700 } 00701 else if (status == -1) { 00702 log_msg(config, LOG_INFO, "Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days", temp_char); 00703 } 00704 config->interval = mysec; 00705 if (verbose) { 00706 log_msg(config, LOG_INFO, "Communication Interval: %i", config->interval); 00707 } 00708 StrFree(temp_char); 00709 xmlXPathFreeObject(xpathObj); 00710 00711 /* Evaluate xpath expression for Manual key generation */ 00712 xpathObj = xmlXPathEvalExpression(mk_expr, xpathCtx); 00713 if(xpathObj == NULL) { 00714 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mk_expr); 00715 xmlXPathFreeContext(xpathCtx); 00716 xmlFreeDoc(doc); 00717 return(-1); 00718 } 00719 00720 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00721 /* Manual key generation tag is present */ 00722 config->manualKeyGeneration = 1; 00723 } 00724 else { 00725 /* Tag absent */ 00726 config->manualKeyGeneration = 0; 00727 } 00728 xmlXPathFreeObject(xpathObj); 00729 00730 /* Evaluate xpath expression for rollover notification interval */ 00731 xpathObj = xmlXPathEvalExpression(rn_expr, xpathCtx); 00732 if(xpathObj == NULL) { 00733 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", rn_expr); 00734 xmlXPathFreeContext(xpathCtx); 00735 xmlFreeDoc(doc); 00736 return(-1); 00737 } 00738 00739 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00740 /* Tag RolloverNotification is present; set rolloverNotify */ 00741 temp_char = (char *)xmlXPathCastToString(xpathObj); 00742 status = DtXMLIntervalSeconds(temp_char, &mysec); 00743 if (status > 0) { 00744 log_msg(config, LOG_ERR, "Error: unable to convert RolloverNotification %s to seconds, error: %i", temp_char, status); 00745 StrFree(temp_char); 00746 return status; 00747 } 00748 else if (status == -1) { 00749 log_msg(config, LOG_INFO, "Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days", temp_char); 00750 } 00751 config->rolloverNotify = mysec; 00752 if (verbose) { 00753 log_msg(config, LOG_INFO, "Rollover Notification Interval: %i", config->rolloverNotify); 00754 } 00755 StrFree(temp_char); 00756 xmlXPathFreeObject(xpathObj); 00757 } 00758 else { 00759 /* Tag RolloverNotification absent, set rolloverNotify to -1 */ 00760 config->rolloverNotify = -1; 00761 } 00762 00763 /* Evaluate xpath expression for DelegationSignerSubmitCommand */ 00764 xpathObj = xmlXPathEvalExpression(ds_expr, xpathCtx); 00765 if(xpathObj == NULL) { 00766 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", ds_expr); 00767 xmlXPathFreeContext(xpathCtx); 00768 xmlFreeDoc(doc); 00769 return(-1); 00770 } 00771 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00772 /* Tag DelegationSignerSubmitCommand is present; set DSSubmitCmd */ 00773 if (config->DSSubmitCmd != NULL) { 00774 StrFree(config->DSSubmitCmd); 00775 } 00776 config->DSSubmitCmd = (char *)xmlXPathCastToString(xpathObj); 00777 00778 if (verbose) { 00779 log_msg(config, LOG_INFO, "Using command: %s to submit DS records", config->DSSubmitCmd); 00780 } 00781 xmlXPathFreeObject(xpathObj); 00782 } else { 00783 if (verbose) { 00784 log_msg(config, LOG_INFO, "No DS Submit command supplied"); 00785 } 00786 config->DSSubmitCmd[0] = '\0'; 00787 } 00788 00789 /* Evaluate xpath expression for SQLite file location */ 00790 00791 xpathObj = xmlXPathEvalExpression(litexpr, xpathCtx); 00792 if(xpathObj == NULL) { 00793 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", litexpr); 00794 xmlXPathFreeContext(xpathCtx); 00795 xmlFreeDoc(doc); 00796 return(-1); 00797 } 00798 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00799 db_found = SQLITE_DB; 00800 if (config->schema != NULL) { 00801 StrFree(config->schema); 00802 } 00803 config->schema = xmlXPathCastToString(xpathObj); 00804 if (verbose) { 00805 log_msg(config, LOG_INFO, "SQLite database set to: %s", config->schema); 00806 } 00807 } 00808 xmlXPathFreeObject(xpathObj); 00809 00810 if (db_found == 0) { 00811 db_found = MYSQL_DB; 00812 00813 /* Get all of the MySQL stuff read in too */ 00814 /* HOST */ 00815 xpathObj = xmlXPathEvalExpression(mysql_host, xpathCtx); 00816 if(xpathObj == NULL) { 00817 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_host); 00818 xmlXPathFreeContext(xpathCtx); 00819 xmlFreeDoc(doc); 00820 return(-1); 00821 } 00822 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00823 if (config->host != NULL) { 00824 StrFree(config->host); 00825 } 00826 config->host = xmlXPathCastToString(xpathObj); 00827 if (verbose) { 00828 log_msg(config, LOG_INFO, "MySQL database host set to: %s", config->host); 00829 } 00830 } 00831 xmlXPathFreeObject(xpathObj); 00832 00833 /* PORT */ 00834 xpathObj = xmlXPathEvalExpression(mysql_port, xpathCtx); 00835 if(xpathObj == NULL) { 00836 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_port); 00837 xmlXPathFreeContext(xpathCtx); 00838 xmlFreeDoc(doc); 00839 return(-1); 00840 } 00841 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00842 if (config->port != NULL) { 00843 StrFree(config->port); 00844 } 00845 config->port = xmlXPathCastToString(xpathObj); 00846 if (verbose) { 00847 log_msg(config, LOG_INFO, "MySQL database port set to: %s", config->port); 00848 } 00849 } 00850 xmlXPathFreeObject(xpathObj); 00851 00852 /* SCHEMA */ 00853 xpathObj = xmlXPathEvalExpression(mysql_db, xpathCtx); 00854 if(xpathObj == NULL) { 00855 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_db); 00856 xmlXPathFreeContext(xpathCtx); 00857 xmlFreeDoc(doc); 00858 return(-1); 00859 } 00860 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00861 if (config->schema != NULL) { 00862 StrFree(config->schema); 00863 } 00864 config->schema = xmlXPathCastToString(xpathObj); 00865 if (verbose) { 00866 log_msg(config, LOG_INFO, "MySQL database schema set to: %s", config->schema); 00867 } 00868 } else { 00869 db_found = 0; 00870 } 00871 xmlXPathFreeObject(xpathObj); 00872 00873 /* DB USER */ 00874 xpathObj = xmlXPathEvalExpression(mysql_user, xpathCtx); 00875 if(xpathObj == NULL) { 00876 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_user); 00877 xmlXPathFreeContext(xpathCtx); 00878 xmlFreeDoc(doc); 00879 return(-1); 00880 } 00881 if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00882 if (config->user != NULL) { 00883 StrFree(config->user); 00884 } 00885 config->user = xmlXPathCastToString(xpathObj); 00886 if (verbose) { 00887 log_msg(config, LOG_INFO, "MySQL database user set to: %s", config->user); 00888 } 00889 } else { 00890 db_found = 0; 00891 } 00892 xmlXPathFreeObject(xpathObj); 00893 00894 /* DB PASSWORD */ 00895 xpathObj = xmlXPathEvalExpression(mysql_pass, xpathCtx); 00896 if(xpathObj == NULL) { 00897 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", mysql_pass); 00898 xmlXPathFreeContext(xpathCtx); 00899 xmlFreeDoc(doc); 00900 return(-1); 00901 } 00902 /* password may be blank */ 00903 00904 if (config->password != NULL) { 00905 StrFree(config->password); 00906 } 00907 config->password = xmlXPathCastToString(xpathObj); 00908 if (verbose) { 00909 log_msg(config, LOG_INFO, "MySQL database password set"); 00910 } 00911 xmlXPathFreeObject(xpathObj); 00912 00913 } 00914 00915 /* Check that we found one or the other database */ 00916 if(db_found == 0) { 00917 log_msg(config, LOG_ERR, "Error: unable to find complete database connection expression in %s", filename); 00918 xmlXPathFreeContext(xpathCtx); 00919 xmlFreeDoc(doc); 00920 return(-1); 00921 } 00922 00923 /* Check that we found the right database type */ 00924 if (db_found != DbFlavour()) { 00925 log_msg(config, LOG_ERR, "Error: database in config file %s does not match libksm", filename); 00926 xmlXPathFreeContext(xpathCtx); 00927 xmlFreeDoc(doc); 00928 return(-1); 00929 } 00930 00931 /* Evaluate xpath expression for log facility (user) */ 00932 xpathObj = xmlXPathEvalExpression(log_user_expr, xpathCtx); 00933 if(xpathObj == NULL) { 00934 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s", log_user_expr); 00935 xmlXPathFreeContext(xpathCtx); 00936 xmlFreeDoc(doc); 00937 return(-1); 00938 } 00939 00940 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { 00941 /* tag present */ 00942 logFacilityName = (char *)xmlXPathCastToString(xpathObj); 00943 00944 status = get_log_user(logFacilityName, &my_log_user); 00945 if (status > 0) { 00946 log_msg(config, LOG_ERR, "Error: unable to set log user: %s, error: %i", logFacilityName, status); 00947 StrFree(logFacilityName); 00948 return status; 00949 } 00950 config->log_user = my_log_user; 00951 if (verbose) { 00952 log_msg(config, LOG_INFO, "Log User set to: %s", logFacilityName); 00953 } 00954 00955 } else { 00956 /* tag _not_ present, use default */ 00957 logFacilityName = StrStrdup( (char *)DEFAULT_LOG_FACILITY_STRING ); 00958 config->log_user = DEFAULT_LOG_FACILITY; 00959 if (verbose) { 00960 log_msg(config, LOG_INFO, "Using default log user: %s", logFacilityName); 00961 } 00962 } 00963 00964 xmlXPathFreeObject(xpathObj); 00965 00966 log_switch(my_log_user, logFacilityName, config->program, verbose); 00967 00968 /* Cleanup */ 00969 /* TODO: some other frees are needed */ 00970 xmlXPathFreeContext(xpathCtx); 00971 xmlFreeDoc(doc); 00972 StrFree(logFacilityName); 00973 StrFree(filename); 00974 00975 return(0); 00976 00977 } 00978 00979 /* To overcome the potential differences in sqlite compile flags assume that it is not 00980 happy with multiple connections. 00981 00982 The following 2 functions take out a lock and release it 00983 */ 00984 00985 int get_lite_lock(char *lock_filename, FILE* lock_fd) 00986 { 00987 struct flock fl; 00988 struct timeval tv; 00989 00990 if (lock_fd == NULL) { 00991 log_msg(NULL, LOG_ERR, "%s could not be opened", lock_filename); 00992 return 1; 00993 } 00994 00995 memset(&fl, 0, sizeof(struct flock)); 00996 fl.l_type = F_WRLCK; 00997 fl.l_whence = SEEK_SET; 00998 fl.l_pid = getpid(); 00999 01000 while (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) { 01001 if (errno == EACCES || errno == EAGAIN) { 01002 log_msg(NULL, LOG_INFO, "%s already locked, sleep", lock_filename); 01003 01004 /* sleep for 10 seconds TODO make this configurable? */ 01005 tv.tv_sec = 10; 01006 tv.tv_usec = 0; 01007 select(0, NULL, NULL, NULL, &tv); 01008 01009 } else { 01010 log_msg(NULL, LOG_INFO, "couldn't get lock on %s, %s", lock_filename, strerror(errno)); 01011 return 1; 01012 } 01013 } 01014 01015 return 0; 01016 01017 } 01018 01019 int release_lite_lock(FILE* lock_fd) 01020 { 01021 struct flock fl; 01022 01023 if (lock_fd == NULL) { 01024 return 1; 01025 } 01026 01027 memset(&fl, 0, sizeof(struct flock)); 01028 fl.l_type = F_UNLCK; 01029 fl.l_whence = SEEK_SET; 01030 01031 if (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) { 01032 return 1; 01033 } 01034 01035 return 0; 01036 } 01037 01038 /* convert the name of a log facility (user) into a number */ 01039 int get_log_user(const char* username, int* usernumber) 01040 { 01041 char* case_username = NULL; 01042 01043 if (username == NULL) { 01044 return 1; 01045 } 01046 /* Start with our default */ 01047 *usernumber = DEFAULT_LOG_FACILITY; 01048 01049 case_username = StrStrdup(username); 01050 (void) StrToUpper(case_username); 01051 01052 /* POSIX only specifies LOG_USER and LOG_LOCAL[0 .. 7] */ 01053 if (strncmp(case_username, "USER", 4) == 0) { 01054 *usernumber = LOG_USER; 01055 } 01056 #ifdef LOG_KERN 01057 else if (strncmp(case_username, "KERN", 4) == 0) { 01058 *usernumber = LOG_KERN; 01059 } 01060 #endif /* LOG_KERN */ 01061 #ifdef LOG_MAIL 01062 else if (strncmp(case_username, "MAIL", 4) == 0) { 01063 *usernumber = LOG_MAIL; 01064 } 01065 #endif /* LOG_MAIL */ 01066 #ifdef LOG_DAEMON 01067 else if (strncmp(case_username, "DAEMON", 6) == 0) { 01068 *usernumber = LOG_DAEMON; 01069 } 01070 #endif /* LOG_DAEMON */ 01071 #ifdef LOG_AUTH 01072 else if (strncmp(case_username, "AUTH", 4) == 0) { 01073 *usernumber = LOG_AUTH; 01074 } 01075 #endif /* LOG_AUTH */ 01076 #ifdef LOG_SYSLOG 01077 else if (strncmp(case_username, "SYSLOG", 6) == 0) { 01078 *usernumber = LOG_SYSLOG; 01079 } 01080 #endif /* LOG_SYSLOG */ 01081 #ifdef LOG_LPR 01082 else if (strncmp(case_username, "LPR", 3) == 0) { 01083 *usernumber = LOG_LPR; 01084 } 01085 #endif /* LOG_LPR */ 01086 #ifdef LOG_NEWS 01087 else if (strncmp(case_username, "NEWS", 4) == 0) { 01088 *usernumber = LOG_NEWS; 01089 } 01090 #endif /* LOG_NEWS */ 01091 #ifdef LOG_UUCP 01092 else if (strncmp(case_username, "UUCP", 4) == 0) { 01093 *usernumber = LOG_UUCP; 01094 } 01095 #endif /* LOG_UUCP */ 01096 #ifdef LOG_AUDIT /* Ubuntu at least doesn't want us to use LOG_AUDIT */ 01097 else if (strncmp(case_username, "AUDIT", 5) == 0) { 01098 *usernumber = LOG_AUDIT; 01099 } 01100 #endif /* LOG_AUDIT */ 01101 #ifdef LOG_CRON 01102 else if (strncmp(case_username, "CRON", 4) == 0) { 01103 *usernumber = LOG_CRON; 01104 } 01105 #endif /* LOG_CRON */ 01106 else if (strncmp(case_username, "LOCAL0", 6) == 0) { 01107 *usernumber = LOG_LOCAL0; 01108 } 01109 else if (strncmp(case_username, "LOCAL1", 6) == 0) { 01110 *usernumber = LOG_LOCAL1; 01111 } 01112 else if (strncmp(case_username, "LOCAL2", 6) == 0) { 01113 *usernumber = LOG_LOCAL2; 01114 } 01115 else if (strncmp(case_username, "LOCAL3", 6) == 0) { 01116 *usernumber = LOG_LOCAL3; 01117 } 01118 else if (strncmp(case_username, "LOCAL4", 6) == 0) { 01119 *usernumber = LOG_LOCAL4; 01120 } 01121 else if (strncmp(case_username, "LOCAL5", 6) == 0) { 01122 *usernumber = LOG_LOCAL5; 01123 } 01124 else if (strncmp(case_username, "LOCAL6", 6) == 0) { 01125 *usernumber = LOG_LOCAL6; 01126 } 01127 else if (strncmp(case_username, "LOCAL7", 6) == 0) { 01128 *usernumber = LOG_LOCAL7; 01129 } 01130 01131 StrFree(case_username); 01132 01133 return 0; 01134 01135 } 01136