• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/srv/bpo/opendnssec/opendnssec-1.3.2/enforcer/common/daemon_util.c

Go to the documentation of this file.
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 

Generated on Mon Oct 31 2011 14:38:30 for OpenDNSSEC-enforcer by  doxygen 1.7.1