OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-mips-p9AT07/opendnssec-1.2.1.dfsg/signer/src/daemon/engine.c

Go to the documentation of this file.
00001 /*
00002  * $Id: engine.c 4441 2011-02-15 09:48:22Z rb $
00003  *
00004  * Copyright (c) 2009 NLNet Labs. 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 
00034 #include "config.h"
00035 #include "daemon/cmdhandler.h"
00036 #include "daemon/cfg.h"
00037 #include "daemon/engine.h"
00038 #include "daemon/signal.h"
00039 #include "daemon/worker.h"
00040 #include "scheduler/locks.h"
00041 #include "scheduler/task.h"
00042 #include "signer/zone.h"
00043 #include "signer/zonelist.h"
00044 #include "tools/zone_fetcher.h"
00045 #include "util/file.h"
00046 #include "util/log.h"
00047 #include "util/privdrop.h"
00048 #include "util/se_malloc.h"
00049 
00050 #include <errno.h>
00051 #include <libhsm.h> /* hsm_open(), hsm_close() */
00052 #include <libxml/parser.h> /* xmlInitParser(), xmlCleanupParser(), xmlCleanupThreads() */
00053 #include <signal.h> /* sigfillset(), sigaction(), kill() */
00054 #include <stdio.h> /* snprintf() */
00055 #include <stdlib.h> /* exit(), fwrite() */
00056 #include <string.h> /* strlen(), strncpy(), strerror() */
00057 #include <strings.h> /* bzero() */
00058 #include <sys/socket.h> /* socket(), connect(), close()  */
00059 #include <sys/types.h> /* getpid(), kill() */
00060 #include <sys/un.h> /* unix socket */
00061 #include <time.h> /* tzset() */
00062 #include <unistd.h> /* fork(), setsid(), getpid(), chdir() */
00063 
00064 
00069 engine_type*
00070 engine_create(void)
00071 {
00072     engine_type* engine = (engine_type*) se_malloc(sizeof(engine_type));
00073 
00074     se_log_debug("create signer engine");
00075     engine->config = NULL;
00076     engine->daemonize = 0;
00077     engine->zonelist = NULL;
00078     engine->tasklist = NULL;
00079     engine->workers = NULL;
00080     engine->cmdhandler = NULL;
00081     engine->cmdhandler_done = 0;
00082     engine->pid = -1;
00083     engine->zfpid = -1;
00084     engine->uid = -1;
00085     engine->gid = -1;
00086     engine->need_to_exit = 0;
00087     engine->need_to_reload = 0;
00088     lock_basic_init(&engine->signal_lock);
00089     lock_basic_set(&engine->signal_cond);
00090     return engine;
00091 }
00092 
00093 
00098 static void*
00099 cmdhandler_thread_start(void* arg)
00100 {
00101     cmdhandler_type* cmd = (cmdhandler_type*) arg;
00102 
00103     se_thread_blocksigs();
00104     cmdhandler_start(cmd);
00105     return NULL;
00106 }
00107 
00108 
00113 static int
00114 engine_start_cmdhandler(engine_type* engine)
00115 {
00116     se_log_assert(engine);
00117     se_log_debug("start command handler");
00118 
00119     engine->cmdhandler->engine = engine;
00120     se_thread_create(&engine->cmdhandler->thread_id,
00121         cmdhandler_thread_start, engine->cmdhandler);
00122     return 0;
00123 }
00124 
00125 
00130 static int
00131 self_pipe_trick(engine_type* engine)
00132 {
00133     int sockfd, ret;
00134     struct sockaddr_un servaddr;
00135     const char* servsock_filename = ODS_SE_SOCKFILE;
00136 
00137     se_log_assert(engine);
00138     se_log_assert(engine->cmdhandler);
00139 
00140     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
00141     if (sockfd <= 0) {
00142         se_log_error("cannot connect to command handler: "
00143             "socket() failed: %s\n", strerror(errno));
00144         return 1;
00145     } else {
00146         bzero(&servaddr, sizeof(servaddr));
00147         servaddr.sun_family = AF_UNIX;
00148         strncpy(servaddr.sun_path, servsock_filename,
00149             sizeof(servaddr.sun_path) - 1);
00150 
00151         ret = connect(sockfd, (const struct sockaddr*) &servaddr,
00152             sizeof(servaddr));
00153         if (ret != 0) {
00154             se_log_error("cannot connect to command handler: "
00155                 "connect() failed: %s\n", strerror(errno));
00156             close(sockfd);
00157             return 1;
00158         } else {
00159             /* self-pipe trick */
00160             se_writen(sockfd, "", 1);
00161             close(sockfd);
00162         }
00163     }
00164     return 0;
00165 }
00166 
00167 
00172 static void
00173 engine_stop_cmdhandler(engine_type* engine)
00174 {
00175     se_log_assert(engine);
00176     se_log_assert(engine->cmdhandler);
00177     se_log_debug("stop command handler");
00178 
00179     engine->cmdhandler->need_to_exit = 1;
00180     if (self_pipe_trick(engine) == 0) {
00181         while (!engine->cmdhandler_done) {
00182             se_log_debug("waiting for command handler to exit...");
00183             sleep(1);
00184         }
00185     } else {
00186         se_log_error("command handler self pipe trick failed, "
00187             "unclean shutdown");
00188     }
00189     return;
00190 }
00191 
00192 
00197 static int
00198 engine_privdrop(engine_type* engine)
00199 {
00200     int error;
00201 
00202     se_log_assert(engine);
00203     se_log_assert(engine->config);
00204     se_log_debug("drop privileges");
00205 
00206     if (engine->config->username && engine->config->group) {
00207         se_log_verbose("drop privileges to user %s, group %s",
00208            engine->config->username, engine->config->group);
00209     } else if (engine->config->username) {
00210         se_log_verbose("drop privileges to user %s",
00211            engine->config->username);
00212     } else if (engine->config->group) {
00213         se_log_verbose("drop privileges to group %s",
00214            engine->config->group);
00215     }
00216     if (engine->config->chroot) {
00217         se_log_verbose("chroot to %s", engine->config->chroot);
00218     }
00219     error = privdrop(engine->config->username, engine->config->group,
00220         engine->config->chroot);
00221     return error;
00222 }
00223 
00224 
00229 static void
00230 parent_cleanup(engine_type* engine, int keep_pointer)
00231 {
00232     if (engine) {
00233         if (engine->config) {
00234             engine_config_cleanup(engine->config);
00235             engine->config = NULL;
00236         }
00237         if (!keep_pointer) {
00238             se_free((void*) engine);
00239         }
00240     } else {
00241         se_log_warning("cleanup empty parent");
00242     }
00243 }
00244 
00245 
00250 static int
00251 write_pidfile(const char* pidfile, pid_t pid)
00252 {
00253     FILE* fd;
00254     char pidbuf[32];
00255     size_t result = 0, size = 0;
00256 
00257     se_log_assert(pidfile);
00258     se_log_assert(pid);
00259     se_log_debug("writing pid %lu to pidfile %s", (unsigned long) pid,
00260         pidfile?pidfile:"(null)");
00261     snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) pid);
00262     fd = se_fopen(pidfile, NULL, "w");
00263     if (!fd) {
00264         return -1;
00265     }
00266     size = strlen(pidbuf);
00267     if (size == 0) {
00268         result = 1;
00269     } else {
00270         result = fwrite((const void*) pidbuf, 1, size, fd);
00271     }
00272     if (result == 0) {
00273         se_log_error("write to pidfile %s failed: %s", pidfile?pidfile:"(null)",
00274             strerror(errno));
00275     } else if (result < size) {
00276         se_log_error("short write to pidfile %s: disk full?",
00277             pidfile?pidfile:"(null)");
00278         result = 0;
00279     } else {
00280         result = 1;
00281     }
00282     se_fclose(fd);
00283     if (!result) {
00284         return -1;
00285     }
00286     return 0;
00287 }
00288 
00289 
00294 static void
00295 engine_create_workers(engine_type* engine)
00296 {
00297     size_t i = 0;
00298 
00299     se_log_assert(engine);
00300     se_log_assert(engine->config);
00301     engine->workers = (worker_type**)
00302         se_calloc((size_t)engine->config->num_worker_threads,
00303         sizeof(worker_type*));
00304 
00305     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00306         engine->workers[i] = worker_create(i, WORKER_WORKER);
00307         engine->workers[i]->tasklist = engine->tasklist;
00308     }
00309     return;
00310 }
00311 
00312 
00317 static void*
00318 worker_thread_start(void* arg)
00319 {
00320     worker_type* worker = (worker_type*) arg;
00321     se_thread_blocksigs();
00322     worker_start(worker);
00323     return NULL;
00324 }
00325 
00326 
00331 static void
00332 engine_start_workers(engine_type* engine)
00333 {
00334     size_t i = 0;
00335 
00336     se_log_assert(engine);
00337     se_log_assert(engine->config);
00338     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00339         engine->workers[i]->need_to_exit = 0;
00340         engine->workers[i]->engineptr = (struct engine_struct*) engine;
00341         se_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
00342             engine->workers[i]);
00343     }
00344     return;
00345 }
00346 
00347 
00352 static void
00353 engine_stop_workers(engine_type* engine)
00354 {
00355     size_t i = 0;
00356 
00357     se_log_assert(engine);
00358     se_log_assert(engine->config);
00359     se_log_debug("stop workers");
00360 
00361     /* tell them to exit and wake up sleepyheads */
00362     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00363         engine->workers[i]->need_to_exit = 1;
00364         worker_wakeup(engine->workers[i]);
00365     }
00366     /* head count */
00367     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00368         se_thread_join(engine->workers[i]->thread_id);
00369         engine->workers[i]->engineptr = NULL;
00370     }
00371     return;
00372 }
00373 
00374 
00379 int
00380 engine_search_workers(engine_type* engine, const char* zone_name)
00381 {
00382     size_t i = 0;
00383 
00384     se_log_assert(engine);
00385     se_log_assert(engine->config);
00386 
00387     if (!zone_name) {
00388         return 1;
00389     }
00390 
00391     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00392         if (engine->workers[i]->task &&
00393             se_strcmp(engine->workers[i]->task->who, zone_name) == 0) {
00394             /* ba-da bing */
00395             return 0;
00396         }
00397     }
00398     /* no potato */
00399     return 1;
00400 }
00401 
00402 
00407 static int
00408 start_zonefetcher(engine_type* engine)
00409 {
00410     pid_t zfpid = 0;
00411     int result = 0;
00412     char* zf_filename = NULL;
00413     char* zl_filename = NULL;
00414     char* log_filename = NULL;
00415     char* grp = NULL;
00416     char* usr = NULL;
00417     char* chrt = NULL;
00418     int use_syslog = 0;
00419     int verbosity = 0;
00420 
00421     se_log_assert(engine);
00422     se_log_assert(engine->config);
00423 
00424     if (!engine->config->zonefetch_filename) {
00425         /* zone fetcher disabled */
00426         return 0;
00427     }
00428 
00429     switch ((zfpid = fork())) {
00430         case -1: /* error */
00431             se_log_error("failed to fork zone fetcher: %s",
00432                 strerror(errno));
00433             return 1;
00434         case 0: /* child */
00435             break;
00436         default: /* parent */
00437             engine->zfpid = zfpid;
00438             return 0;
00439     }
00440 
00441     if (setsid() == -1) {
00442         se_log_error("failed to setsid zone fetcher: %s",
00443             strerror(errno));
00444         return 1;
00445     }
00446 
00447     hsm_close();
00448     se_log_verbose("zone fetcher running as pid %lu",
00449         (unsigned long) getpid());
00450 
00451     zf_filename = se_strdup(engine->config->zonefetch_filename);
00452     zl_filename = se_strdup(engine->config->zonelist_filename);
00453     grp = se_strdup(engine->config->group);
00454     usr = se_strdup(engine->config->username);
00455     chrt = se_strdup(engine->config->chroot);
00456     log_filename = se_strdup(engine->config->log_filename);
00457     use_syslog = engine->config->use_syslog;
00458     verbosity = engine->config->verbosity;
00459 
00460     result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
00461         chrt, log_filename, use_syslog, verbosity);
00462 
00463     se_log_verbose("zone fetcher done", result);
00464     if (zf_filename)  { se_free((void*)zf_filename); }
00465     if (zl_filename)  { se_free((void*)zl_filename); }
00466     if (grp)          { se_free((void*)grp); }
00467     if (usr)          { se_free((void*)usr); }
00468     if (chrt)         { se_free((void*)chrt); }
00469     if (log_filename) { se_free((void*)log_filename); }
00470 
00471     cmdhandler_cleanup(engine->cmdhandler);
00472     engine_cleanup(engine);
00473     engine = NULL;
00474     se_log_close();
00475     xmlCleanupParser();
00476     xmlCleanupGlobals();
00477     xmlCleanupThreads();
00478     exit(result);
00479 
00480     return 0;
00481 }
00482 
00483 
00488 static void
00489 reload_zonefetcher(engine_type* engine)
00490 {
00491     int result = 0;
00492 
00493     se_log_assert(engine);
00494     se_log_assert(engine->config);
00495 
00496     if (engine->config->zonefetch_filename) {
00497         if (engine->zfpid > 0) {
00498             result = kill(engine->zfpid, SIGHUP);
00499             if (result == -1) {
00500                 se_log_error("cannot reload zone fetcher: %s", strerror(errno));
00501             } else {
00502                 se_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
00503             }
00504         } else {
00505             se_log_error("cannot reload zone fetcher: process id unknown");
00506         }
00507     }
00508     return;
00509 }
00510 
00511 
00516 static void
00517 stop_zonefetcher(engine_type* engine)
00518 {
00519     int result = 0;
00520 
00521     se_log_assert(engine);
00522     se_log_assert(engine->config);
00523 
00524     if (engine->config->zonefetch_filename) {
00525         if (engine->zfpid > 0) {
00526             result = kill(engine->zfpid, SIGTERM);
00527             if (result == -1) {
00528                 se_log_error("cannot stop zone fetcher: %s", strerror(errno));
00529             } else {
00530                 se_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
00531             }
00532             engine->zfpid = -1;
00533         } else {
00534             se_log_error("cannot stop zone fetcher: process id unknown");
00535         }
00536     }
00537     return;
00538 }
00539 
00540 
00545 static int
00546 engine_setup(engine_type* engine)
00547 {
00548     struct sigaction action;
00549     int result = 0;
00550 
00551     se_log_assert(engine);
00552     se_log_assert(engine->config);
00553     se_log_debug("perform setup");
00554 
00555     /* set up the work floor */
00556     engine->tasklist = tasklist_create(); /* tasks */
00557     engine->zonelist = zonelist_create(); /* zones */
00558     engine_create_workers(engine); /* workers */
00559 
00560     /* create command handler (before chowning socket file) */
00561     engine->cmdhandler = cmdhandler_create(engine->config->clisock_filename);
00562     if (!engine->cmdhandler) {
00563         se_log_error("cannot create cmdhandler");
00564         return 1;
00565     }
00566 
00567     /* fork of fetcher */
00568     if (start_zonefetcher(engine) != 0) {
00569         se_log_error("cannot start zonefetcher");
00570         cmdhandler_cleanup(engine->cmdhandler);
00571         engine->cmdhandler = NULL;
00572         return 1;
00573     }
00574 
00575     /* privdrop */
00576     engine->uid = privuid(engine->config->username);
00577     engine->gid = privgid(engine->config->group);
00578     /* TODO: does piddir exists? */
00579     /* remove the chown stuff: piddir? */
00580     /* chown pidfile directory */
00581     se_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
00582     /* chown sockfile */
00583     se_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
00584     /* chown workdir */
00585     se_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
00586     if (engine->config->log_filename && !engine->config->use_syslog) {
00587         /* chown logfile */
00588         se_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
00589     }
00590     if (engine->config->working_dir &&
00591         chdir(engine->config->working_dir) != 0) {
00592         se_log_error("setup failed: chdir to %s failed: %s",
00593             engine->config->working_dir, strerror(errno));
00594         cmdhandler_cleanup(engine->cmdhandler);
00595         engine->cmdhandler = NULL;
00596         return 1;
00597     }
00598 
00599     if (engine_privdrop(engine) != 0) {
00600         se_log_error("setup failed: unable to drop privileges");
00601         cmdhandler_cleanup(engine->cmdhandler);
00602         engine->cmdhandler = NULL;
00603         return 1;
00604     }
00605 
00606     /* daemonize */
00607     if (engine->daemonize) {
00608         switch ((engine->pid = fork())) {
00609             case -1: /* error */
00610                 se_log_error("setup failed: unable to fork daemon: %s",
00611                     strerror(errno));
00612                 cmdhandler_cleanup(engine->cmdhandler);
00613                 engine->cmdhandler = NULL;
00614                 return 1;
00615             case 0: /* child */
00616                 break;
00617             default: /* parent */
00618                 cmdhandler_cleanup(engine->cmdhandler);
00619                 engine->cmdhandler = NULL;
00620                 parent_cleanup(engine, 0);
00621                 xmlCleanupParser();
00622                 xmlCleanupGlobals();
00623                 xmlCleanupThreads();
00624                 exit(0);
00625         }
00626         if (setsid() == -1) {
00627             se_log_error("setup failed: unable to setsid daemon (%s)",
00628                 strerror(errno));
00629             cmdhandler_cleanup(engine->cmdhandler);
00630             engine->cmdhandler = NULL;
00631             return 1;
00632         }
00633     }
00634     engine->pid = getpid();
00635     /* make common with enforcer */
00636     if (write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
00637         se_log_error("setup failed: unable to write pid file");
00638         cmdhandler_cleanup(engine->cmdhandler);
00639         engine->cmdhandler = NULL;
00640         return 1;
00641     }
00642     se_log_verbose("running as pid %lu", (unsigned long) engine->pid);
00643 
00644     /* start command handler */
00645     if (engine_start_cmdhandler(engine) != 0) {
00646         se_log_error("setup failed: unable to start command handler");
00647         cmdhandler_cleanup(engine->cmdhandler);
00648         engine->cmdhandler = NULL;
00649         return 1;
00650     }
00651 
00652     /* catch signals */
00653     signal_set_engine(engine);
00654     action.sa_handler = signal_handler;
00655     sigfillset(&action.sa_mask);
00656     action.sa_flags = 0;
00657     sigaction(SIGHUP, &action, NULL);
00658     sigaction(SIGTERM, &action, NULL);
00659 
00660     /* set up hsm */
00661     result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL); /* LEAKS */
00662     if (result != HSM_OK) {
00663         se_log_error("setup failed: error initializing libhsm (errno %i)",
00664             result);
00665         cmdhandler_cleanup(engine->cmdhandler);
00666         engine->cmdhandler = NULL;
00667         return 1;
00668     }
00669 
00670     return 0;
00671 }
00672 
00673 
00678 static int
00679 engine_all_zones_processed(engine_type* engine)
00680 {
00681     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00682     zone_type* zone = NULL;
00683 
00684     se_log_assert(engine);
00685     se_log_assert(engine->zonelist);
00686     se_log_assert(engine->zonelist->zones);
00687 
00688     node = ldns_rbtree_first(engine->zonelist->zones);
00689     while (node && node != LDNS_RBTREE_NULL) {
00690         zone = (zone_type*) node->key;
00691         if (!zone->processed) {
00692                 return 0;
00693         }
00694         node = ldns_rbtree_next(node);
00695     }
00696     return 1;
00697 }
00698 
00699 
00704 static void
00705 engine_run(engine_type* engine, int single_run)
00706 {
00707     if (!engine) {
00708         return;
00709     }
00710     se_log_assert(engine);
00711 
00712     engine->signal = SIGNAL_RUN;
00713     while (engine->need_to_exit == 0 && engine->need_to_reload == 0) {
00714         engine->signal = signal_capture(engine->signal);
00715         switch (engine->signal) {
00716             case SIGNAL_RUN:
00717                 se_log_assert(1);
00718                 break;
00719             case SIGNAL_RELOAD:
00720                 engine->need_to_reload = 1;
00721                 break;
00722             case SIGNAL_SHUTDOWN:
00723                 engine->need_to_exit = 1;
00724                 break;
00725             default:
00726                 se_log_warning("invalid signal captured: %d, keep running",
00727                     engine->signal);
00728                 engine->signal = SIGNAL_RUN;
00729                 break;
00730         }
00731 
00732         if (single_run) {
00733            engine->need_to_exit = engine_all_zones_processed(engine);
00734         }
00735 
00736         lock_basic_lock(&engine->signal_lock);
00737         if (engine->signal == SIGNAL_RUN && !single_run) {
00738            se_log_debug("engine taking a break");
00739            lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
00740         }
00741         lock_basic_unlock(&engine->signal_lock);
00742     }
00743     se_log_debug("engine halt");
00744     return;
00745 }
00746 
00747 
00752 int
00753 engine_update_zonelist(engine_type* engine, char* buf)
00754 {
00755     zonelist_type* new_zlist = NULL;
00756 
00757     se_log_assert(engine);
00758     se_log_assert(engine->config);
00759     se_log_assert(engine->zonelist);
00760     se_log_debug("update zone list");
00761 
00762     new_zlist = zonelist_read(engine->config->zonelist_filename,
00763         engine->zonelist->last_modified);
00764     if (!new_zlist) {
00765         if (buf) {
00766             /* fstat <= last_modified || rng check failed */
00767             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed.\n");
00768         }
00769         return 1;
00770     }
00771 
00772     zonelist_lock(engine->zonelist);
00773     zonelist_merge(engine->zonelist, new_zlist);
00774     zonelist_update(engine->zonelist, engine->tasklist, engine->config->notify_command, buf);
00775     zonelist_unlock(engine->zonelist);
00776     return 0;
00777 }
00778 
00779 
00784 void
00785 set_notify_ns(zone_type* zone, const char* cmd)
00786 {
00787     const char* str = NULL;
00788     const char* str2 = NULL;
00789 
00790     se_log_assert(cmd);
00791     se_log_assert(zone);
00792     se_log_assert(zone->name);
00793     se_log_assert(zone->outbound_adapter);
00794     se_log_assert(zone->outbound_adapter->filename);
00795 
00796     str = se_replace(cmd, "%zonefile", zone->outbound_adapter->filename);
00797     str2 = se_replace(str, "%zone", zone->name);
00798     se_free((void*)str);
00799     zone->notify_ns = (const char*) str2;
00800     se_log_debug("set notify ns: %s", zone->notify_ns);
00801 
00802     return;
00803 }
00804 
00805 
00810 int
00811 engine_update_zones(engine_type* engine, const char* zone_name, char* buf,
00812     int first_try)
00813 {
00814     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00815     zone_type* zone = NULL;
00816     int tmp = 0;
00817     int unchanged = 0;
00818     int errors = 0;
00819     int updated = 0;
00820 
00821     se_log_assert(engine);
00822     se_log_assert(engine->zonelist);
00823     se_log_assert(engine->zonelist->zones);
00824 
00825     reload_zonefetcher(engine);
00826 
00827     lock_basic_lock(&engine->tasklist->tasklist_lock);
00828     engine->tasklist->loading = 1;
00829     lock_basic_unlock(&engine->tasklist->tasklist_lock);
00830 
00831     node = ldns_rbtree_first(engine->zonelist->zones);
00832     while (node && node != LDNS_RBTREE_NULL) {
00833         zone = (zone_type*) node->key;
00834 
00835         lock_basic_lock(&zone->zone_lock);
00836 
00837         if (!zone_name || se_strcmp(zone->name, zone_name) == 0) {
00838             if (zone_name) {
00839                 se_log_debug("update zone %s (signconf file %s)", zone->name,
00840                     zone->signconf_filename?zone->signconf_filename:"(null)");
00841                 lock_basic_lock(&engine->tasklist->tasklist_lock);
00842                 tmp = zone_update_signconf(zone, engine->tasklist, buf);
00843                 zone->fetch = (engine->config->zonefetch_filename != NULL);
00844                 engine->tasklist->loading = 0;
00845 
00846                 lock_basic_unlock(&engine->tasklist->tasklist_lock);
00847                 lock_basic_unlock(&zone->zone_lock);
00848                 return 0;
00849             }
00850 
00851             lock_basic_lock(&engine->tasklist->tasklist_lock);
00852             tmp = zone_update_signconf(zone, engine->tasklist, buf);
00853             zone->fetch = (engine->config->zonefetch_filename != NULL);
00854 
00855             lock_basic_unlock(&engine->tasklist->tasklist_lock);
00856 
00857             if (tmp < 0) {
00858                 errors++;
00859             } else if (tmp > 0) {
00860                 updated++;
00861             } else {
00862                 unchanged++;
00863             }
00864         }
00865 
00866         lock_basic_unlock(&zone->zone_lock);
00867         node = ldns_rbtree_next(node);
00868     }
00869 
00870     lock_basic_lock(&engine->tasklist->tasklist_lock);
00871     engine->tasklist->loading = 0;
00872     lock_basic_unlock(&engine->tasklist->tasklist_lock);
00873 
00874     if (zone_name) {
00875         se_log_debug("zone %s not found", zone_name);
00876         if (buf) {
00877             (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not found%s.\n",
00878             zone_name, first_try?", updating zone list":"");
00879         }
00880         return 1;
00881     } else {
00882         se_log_debug("configurations updated");
00883         if (buf) {
00884             (void)snprintf(buf, ODS_SE_MAXLINE, "Configurations updated: %i; "
00885                 "errors: %i; unchanged: %i.\n", updated, errors, unchanged);
00886         }
00887     }
00888     return 0;
00889 }
00890 
00891 
00896 static void
00897 engine_recover_from_backups(engine_type* engine)
00898 {
00899     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00900     zone_type* zone = NULL;
00901 
00902     se_log_assert(engine);
00903     se_log_assert(engine->zonelist);
00904     se_log_assert(engine->zonelist->zones);
00905 
00906     lock_basic_lock(&engine->tasklist->tasklist_lock);
00907     engine->tasklist->loading = 1;
00908     lock_basic_unlock(&engine->tasklist->tasklist_lock);
00909 
00910     node = ldns_rbtree_first(engine->zonelist->zones);
00911     while (node && node != LDNS_RBTREE_NULL) {
00912         zone = (zone_type*) node->key;
00913         lock_basic_lock(&zone->zone_lock);
00914 
00915         /* set the notify ns command */
00916         if (engine->config->notify_command && !zone->notify_ns) {
00917             set_notify_ns(zone, engine->config->notify_command);
00918         }
00919 
00920         lock_basic_lock(&engine->tasklist->tasklist_lock);
00921         zone_recover_from_backup(zone, engine->tasklist);
00922         lock_basic_unlock(&engine->tasklist->tasklist_lock);
00923         lock_basic_unlock(&zone->zone_lock);
00924         node = ldns_rbtree_next(node);
00925     }
00926 
00927     lock_basic_lock(&engine->tasklist->tasklist_lock);
00928     engine->tasklist->loading = 0;
00929     lock_basic_unlock(&engine->tasklist->tasklist_lock);
00930 
00931     return;
00932 }
00933 
00934 
00939 void
00940 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
00941     int info, int single_run)
00942 {
00943     engine_type* engine = NULL;
00944     int use_syslog = 0;
00945     int zl_changed = 0;
00946 
00947     se_log_assert(cfgfile);
00948     se_log_init(NULL, use_syslog, cmdline_verbosity);
00949     se_log_verbose("start signer engine");
00950 
00951     /* initialize */
00952     xmlInitGlobals();
00953     xmlInitParser();
00954     engine = engine_create();
00955     engine->daemonize = daemonize;
00956 
00957     /* configure */
00958     engine->config = engine_config(cfgfile, cmdline_verbosity);
00959     if (engine_check_config(engine->config) != 0) {
00960         se_log_error("cfgfile %s has errors", cfgfile?cfgfile:"(null)");
00961         goto earlyexit;
00962     }
00963     if (info) {
00964         engine_config_print(stdout, engine->config); /* for debugging */
00965         goto earlyexit;
00966     }
00967 
00968     /* open log */
00969     se_log_init(engine->config->log_filename, engine->config->use_syslog,
00970        engine->config->verbosity);
00971 
00972     /* setup */
00973     tzset(); /* for portability */
00974     if (engine_setup(engine) != 0) {
00975         se_log_error("signer engine setup failed");
00976         engine->need_to_exit = 1;
00977     }
00978 
00979     /* run */
00980     while (engine->need_to_exit == 0) {
00981         zl_changed = (engine_update_zonelist(engine, NULL) == 0);
00982 
00983         if (engine->need_to_reload) {
00984             se_log_info("reload engine");
00985             engine->need_to_reload = 0;
00986         } else {
00987             se_log_info("signer engine started");
00988             /* try to recover from backups */
00989             engine_recover_from_backups(engine);
00990         }
00991 
00992         if (zl_changed) {
00993             zl_changed = engine_update_zones(engine, NULL, NULL, 0);
00994             zl_changed = 0;
00995         }
00996 
00997         engine_start_workers(engine);
00998         engine_run(engine, single_run);
00999         engine_stop_workers(engine);
01000     }
01001 
01002     /* shutdown */
01003     se_log_info("shutdown signer engine");
01004     stop_zonefetcher(engine);
01005     hsm_close();
01006     if (engine->cmdhandler != NULL) {
01007         engine_stop_cmdhandler(engine);
01008     }
01009 
01010     (void)unlink(engine->config->pid_filename);
01011     (void)unlink(engine->config->clisock_filename);
01012 
01013 earlyexit:
01014     engine_cleanup(engine);
01015     engine = NULL;
01016     se_log_close();
01017     xmlCleanupParser();
01018     xmlCleanupGlobals();
01019     xmlCleanupThreads();
01020     return;
01021 }
01022 
01023 
01028 void
01029 engine_cleanup(engine_type* engine)
01030 {
01031     size_t i = 0;
01032 
01033     if (engine) {
01034         se_log_debug("clean up engine");
01035         if (engine->workers) {
01036             for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
01037                 worker_cleanup(engine->workers[i]);
01038             }
01039             se_free((void*) engine->workers);
01040         }
01041         if (engine->tasklist) {
01042             tasklist_cleanup(engine->tasklist);
01043             engine->tasklist = NULL;
01044         }
01045         if (engine->zonelist) {
01046             zonelist_cleanup(engine->zonelist);
01047             engine->zonelist = NULL;
01048         }
01049         parent_cleanup(engine, 1);
01050         lock_basic_destroy(&engine->signal_lock);
01051         lock_basic_off(&engine->signal_cond);
01052         se_free((void*) engine);
01053     } else {
01054         se_log_warning("cleanup empty engine");
01055     }
01056     return;
01057 }