"Fossies" - the Fresh Open Source Software Archive

Member "opendnssec-2.1.4/signer/src/daemon/engine.c" (16 May 2019, 30170 Bytes) of package /linux/misc/dns/opendnssec-2.1.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "engine.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.1.0_vs_2.1.1.

    1 /*
    2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  */
   26 
   27 /**
   28  * The engine.
   29  *
   30  */
   31 
   32 #include "config.h"
   33 #include "daemon/cfg.h"
   34 #include "daemon/engine.h"
   35 #include "duration.h"
   36 #include "file.h"
   37 #include "str.h"
   38 #include "hsm.h"
   39 #include "locks.h"
   40 #include "log.h"
   41 #include "privdrop.h"
   42 #include "status.h"
   43 #include "util.h"
   44 #include "signer/zonelist.h"
   45 #include "wire/tsig.h"
   46 #include "libhsm.h"
   47 #include "signertasks.h"
   48 #include "signercommands.h"
   49 
   50 #include <errno.h>
   51 #include <libxml/parser.h>
   52 #include <signal.h>
   53 #include <stdio.h>
   54 #include <stdlib.h>
   55 #include <string.h>
   56 #include <strings.h>
   57 #include <sys/socket.h>
   58 #include <sys/types.h>
   59 #include <sys/un.h>
   60 #include <time.h>
   61 #include <unistd.h>
   62 
   63 static const char* engine_str = "engine";
   64 
   65 static engine_type* engine = NULL;
   66 
   67 /**
   68  * Create engine.
   69  *
   70  */
   71 static engine_type*
   72 engine_create(void)
   73 {
   74     engine_type* engine;
   75     CHECKALLOC(engine = (engine_type*) malloc(sizeof(engine_type)));
   76     engine->config = NULL;
   77     engine->workers = NULL;
   78     engine->cmdhandler = NULL;
   79     engine->dnshandler = NULL;
   80     engine->xfrhandler = NULL;
   81     engine->taskq = NULL;
   82     engine->pid = -1;
   83     engine->uid = -1;
   84     engine->gid = -1;
   85     engine->daemonize = 0;
   86     engine->need_to_exit = 0;
   87     engine->need_to_reload = 0;
   88     pthread_mutex_init(&engine->signal_lock, NULL);
   89     pthread_cond_init(&engine->signal_cond, NULL);
   90     engine->zonelist = zonelist_create();
   91     if (!engine->zonelist) {
   92         engine_cleanup(engine);
   93         return NULL;
   94     }
   95     if (!(engine->taskq = schedule_create())) {
   96         engine_cleanup(engine);
   97         return NULL;
   98     }
   99     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_SIGNCONF, do_readsignconf);
  100     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_FORCESIGNCONF, do_forcereadsignconf);
  101     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_READ, do_readzone);
  102     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_FORCEREAD, do_forcereadzone);
  103     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_SIGN, do_signzone);
  104     schedule_registertask(engine->taskq, TASK_CLASS_SIGNER, TASK_WRITE, do_writezone);
  105     return engine;
  106 }
  107 
  108 static void
  109 engine_start_cmdhandler(engine_type* engine)
  110 {
  111     ods_log_debug("[%s] start command handler", engine_str);
  112     janitor_thread_create(&engine->cmdhandler->thread_id, workerthreadclass, (janitor_runfn_t)cmdhandler_start, engine->cmdhandler);
  113 }
  114 
  115 /**
  116  * Start/stop dnshandler.
  117  *
  118  */
  119 static void
  120 engine_start_dnshandler(engine_type* engine)
  121 {
  122     if (!engine || !engine->dnshandler) {
  123         return;
  124     }
  125     ods_log_debug("[%s] start dnshandler", engine_str);
  126     engine->dnshandler->engine = engine;
  127     janitor_thread_create(&engine->dnshandler->thread_id, handlerthreadclass, (janitor_runfn_t)dnshandler_start, engine->dnshandler);
  128 }
  129 static void
  130 engine_stop_dnshandler(engine_type* engine)
  131 {
  132     if (!engine || !engine->dnshandler || !engine->dnshandler->thread_id) {
  133         return;
  134     }
  135     ods_log_debug("[%s] stop dnshandler", engine_str);
  136     engine->dnshandler->need_to_exit = 1;
  137     dnshandler_signal(engine->dnshandler);
  138     ods_log_debug("[%s] join dnshandler", engine_str);
  139     janitor_thread_join(engine->dnshandler->thread_id);
  140     engine->dnshandler->engine = NULL;
  141 }
  142 
  143 
  144 static void
  145 engine_start_xfrhandler(engine_type* engine)
  146 {
  147     if (!engine || !engine->xfrhandler) {
  148         return;
  149     }
  150     ods_log_debug("[%s] start xfrhandler", engine_str);
  151     engine->xfrhandler->engine = engine;
  152     /* This might be the wrong place to mark the xfrhandler started but
  153      * if its isn't done here we might try to shutdown and stop it before
  154      * it has marked itself started
  155      */
  156     engine->xfrhandler->started = 1;
  157     janitor_thread_create(&engine->xfrhandler->thread_id, handlerthreadclass, (janitor_runfn_t)xfrhandler_start, engine->xfrhandler);
  158 }
  159 static void
  160 engine_stop_xfrhandler(engine_type* engine)
  161 {
  162     if (!engine || !engine->xfrhandler) {
  163         return;
  164     }
  165     ods_log_debug("[%s] stop xfrhandler", engine_str);
  166     engine->xfrhandler->need_to_exit = 1;
  167     xfrhandler_signal(engine->xfrhandler);
  168     ods_log_debug("[%s] join xfrhandler", engine_str);
  169     if (engine->xfrhandler->started) {
  170         janitor_thread_join(engine->xfrhandler->thread_id);
  171         engine->xfrhandler->started = 0;
  172     }
  173     engine->xfrhandler->engine = NULL;
  174 }
  175 
  176 
  177 /**
  178  * Drop privileges.
  179  *
  180  */
  181 static ods_status
  182 engine_privdrop(engine_type* engine)
  183 {
  184     ods_status status = ODS_STATUS_OK;
  185     uid_t uid = -1;
  186     gid_t gid = -1;
  187     ods_log_assert(engine);
  188     ods_log_assert(engine->config);
  189     ods_log_debug("[%s] drop privileges", engine_str);
  190     if (engine->config->username && engine->config->group) {
  191         ods_log_verbose("[%s] drop privileges to user %s, group %s",
  192            engine_str, engine->config->username, engine->config->group);
  193     } else if (engine->config->username) {
  194         ods_log_verbose("[%s] drop privileges to user %s", engine_str,
  195            engine->config->username);
  196     } else if (engine->config->group) {
  197         ods_log_verbose("[%s] drop privileges to group %s", engine_str,
  198            engine->config->group);
  199     }
  200     if (engine->config->chroot) {
  201         ods_log_verbose("[%s] chroot to %s", engine_str,
  202             engine->config->chroot);
  203     }
  204     status = privdrop(engine->config->username, engine->config->group,
  205         engine->config->chroot, &uid, &gid);
  206     engine->uid = uid;
  207     engine->gid = gid;
  208     privclose(engine->config->username, engine->config->group);
  209     return status;
  210 }
  211 
  212 
  213 /**
  214  * Start/stop workers.
  215  *
  216  */
  217 static void
  218 engine_create_workers(engine_type* engine)
  219 {
  220     char* name;
  221     int i;
  222     int numTotalWorkers;
  223     int threadCount = 0;
  224     ods_log_assert(engine);
  225     ods_log_assert(engine->config);
  226     numTotalWorkers = engine->config->num_worker_threads + engine->config->num_signer_threads;
  227     CHECKALLOC(engine->workers = (worker_type**) malloc(numTotalWorkers * sizeof(worker_type*)));
  228     for (i=0; i < engine->config->num_worker_threads; i++) {
  229         asprintf(&name, "worker[%d]", i+1);
  230         engine->workers[threadCount++] = worker_create(name, engine->taskq);
  231     }
  232     for (i=0; i < engine->config->num_signer_threads; i++) {
  233         asprintf(&name, "drudger[%d]", i+1);
  234         engine->workers[threadCount++] = worker_create(name, engine->taskq);
  235     }
  236 }
  237 
  238 static void
  239 engine_start_workers(engine_type* engine)
  240 {
  241     int i;
  242     int threadCount = 0;
  243     struct worker_context* context;
  244     ods_log_assert(engine);
  245     ods_log_assert(engine->config);
  246     ods_log_debug("[%s] start workers", engine_str);
  247     for (i=0; i < engine->config->num_worker_threads; i++,threadCount++) {
  248         CHECKALLOC(context = malloc(sizeof(struct worker_context)));
  249         context->engine = engine;
  250         context->worker = engine->workers[threadCount];
  251         context->signq = engine->taskq->signq;
  252         engine->workers[threadCount]->need_to_exit = 0;
  253         engine->workers[threadCount]->context = context;
  254         janitor_thread_create(&engine->workers[threadCount]->thread_id, workerthreadclass, (janitor_runfn_t)worker_start, engine->workers[threadCount]);
  255     }
  256     for (i=0; i < engine->config->num_signer_threads; i++,threadCount++) {
  257         engine->workers[threadCount]->need_to_exit = 0;
  258         janitor_thread_create(&engine->workers[threadCount]->thread_id, workerthreadclass, (janitor_runfn_t)drudge, engine->workers[threadCount]);
  259     }
  260 }
  261 
  262 static void
  263 engine_stop_threads(engine_type* engine)
  264 {
  265     int i;
  266     int numTotalWorkers;
  267     ods_log_assert(engine);
  268     ods_log_assert(engine->config);
  269     ods_log_debug("[%s] stop workers and drudgers", engine_str);
  270     numTotalWorkers = engine->config->num_worker_threads + engine->config->num_signer_threads;
  271     for (i=0; i < numTotalWorkers; i++) {
  272         engine->workers[i]->need_to_exit = 1;
  273     }
  274     ods_log_debug("[%s] notify workers and drudgers", engine_str);
  275     schedule_release_all(engine->taskq);
  276 
  277     for (i=0; i < numTotalWorkers; i++) {
  278         ods_log_debug("[%s] join worker %d", engine_str, i+1);
  279         janitor_thread_join(engine->workers[i]->thread_id);
  280         free(engine->workers[i]->context);
  281     }
  282 }
  283 
  284 
  285 /**
  286  * Wake up all workers.
  287  *
  288  */
  289 void
  290 engine_wakeup_workers(engine_type* engine)
  291 {
  292     size_t i = 0;
  293     ods_log_assert(engine);
  294     ods_log_assert(engine->config);
  295     ods_log_debug("[%s] wake up workers", engine_str);
  296     /* wake up sleepyheads */
  297     schedule_release_all(engine->taskq);
  298 }
  299 
  300 static void *
  301 signal_handler(sig_atomic_t sig)
  302 {
  303     switch (sig) {
  304         case SIGHUP:
  305             if (engine) {
  306                 engine->need_to_reload = 1;
  307                 pthread_mutex_lock(&engine->signal_lock);
  308                 pthread_cond_signal(&engine->signal_cond);
  309                 pthread_mutex_unlock(&engine->signal_lock);
  310             }
  311             break;
  312         case SIGINT:
  313         case SIGTERM:
  314             if (engine) {
  315                 engine->need_to_exit = 1;
  316                 pthread_mutex_lock(&engine->signal_lock);
  317                 pthread_cond_signal(&engine->signal_cond);
  318                 pthread_mutex_unlock(&engine->signal_lock);
  319             }
  320             break;
  321         default:
  322             break;
  323     }
  324     return NULL;
  325 }
  326 
  327 /**
  328  * Set up engine.
  329  *
  330  */
  331 static ods_status
  332 engine_setup(void)
  333 {
  334     ods_status status = ODS_STATUS_OK;
  335     struct sigaction action;
  336     int sockets[2] = {0,0};
  337     int pipefd[2];
  338     char buff = '\0';
  339     int fd, error;
  340 
  341     ods_log_debug("[%s] setup signer engine", engine_str);
  342     if (!engine || !engine->config) {
  343         return ODS_STATUS_ASSERT_ERR;
  344     }
  345     /* set edns */
  346     edns_init(&engine->edns, EDNS_MAX_MESSAGE_LEN);
  347 
  348     /* create command handler (before chowning socket file) */
  349     engine->cmdhandler = cmdhandler_create(engine->config->clisock_filename, signercommands, engine, NULL, NULL);
  350     if (!engine->cmdhandler) {
  351         return ODS_STATUS_CMDHANDLER_ERR;
  352     }
  353     engine->dnshandler = dnshandler_create(engine->config->interfaces);
  354     engine->xfrhandler = xfrhandler_create();
  355     if (!engine->xfrhandler) {
  356         return ODS_STATUS_XFRHANDLER_ERR;
  357     }
  358     if (engine->dnshandler) {
  359         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == -1) {
  360             return ODS_STATUS_XFRHANDLER_ERR;
  361         }
  362         engine->xfrhandler->dnshandler.fd = sockets[0];
  363         engine->dnshandler->xfrhandler.fd = sockets[1];
  364         status = dnshandler_listen(engine->dnshandler);
  365         if (status != ODS_STATUS_OK) {
  366             ods_log_error("[%s] setup: unable to listen to sockets (%s)",
  367                 engine_str, ods_status2str(status));
  368             return ODS_STATUS_XFRHANDLER_ERR;
  369         }
  370     }
  371     /* privdrop */
  372     engine->uid = privuid(engine->config->username);
  373     engine->gid = privgid(engine->config->group);
  374     /* TODO: does piddir exists? */
  375     /* remove the chown stuff: piddir? */
  376     ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
  377     ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
  378     ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
  379     if (engine->config->log_filename && !engine->config->use_syslog) {
  380         ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
  381     }
  382     if (engine->config->working_dir &&
  383         chdir(engine->config->working_dir) != 0) {
  384         ods_log_error("[%s] setup: unable to chdir to %s (%s)", engine_str,
  385             engine->config->working_dir, strerror(errno));
  386         return ODS_STATUS_CHDIR_ERR;
  387     }
  388     if (engine_privdrop(engine) != ODS_STATUS_OK) {
  389         return ODS_STATUS_PRIVDROP_ERR;
  390     }
  391     /* daemonize */
  392     if (engine->daemonize) {
  393         if (pipe(pipefd)) {
  394             ods_log_error("[%s] unable to pipe: %s", engine_str, strerror(errno));
  395             return ODS_STATUS_PIPE_ERR;
  396         }
  397         switch ((engine->pid = fork())) {
  398             case -1: /* error */
  399                 ods_log_error("[%s] setup: unable to fork daemon (%s)",
  400                     engine_str, strerror(errno));
  401                 return ODS_STATUS_FORK_ERR;
  402             case 0: /* child */
  403                 close(pipefd[0]);
  404                 break;
  405             default: /* parent */
  406                 engine_cleanup(engine);
  407                 engine = NULL;
  408                 xmlCleanupParser();
  409                 xmlCleanupGlobals();
  410                 close(pipefd[1]);
  411                 while (read(pipefd[0], &buff, 1) != -1) {
  412                     if (buff <= 1) break;
  413                     printf("%c", buff);
  414                 }
  415                 close(pipefd[0]);
  416                 if (buff == '\1') {
  417                     ods_log_debug("[%s] signerd started successfully", engine_str);
  418                     exit(0);
  419                 }
  420                 ods_log_error("[%s] fail to start signerd completely", engine_str);
  421                 exit(1);
  422         }
  423         if (setsid() == -1) {
  424             ods_log_error("[%s] setup: unable to setsid daemon (%s)",
  425                 engine_str, strerror(errno));
  426             const char *err = "unable to setsid daemon: ";
  427             ods_writen(pipefd[1], err, strlen(err));
  428             ods_writeln(pipefd[1], strerror(errno));
  429             write(pipefd[1], "\0", 1);
  430             close(pipefd[1]);
  431             return ODS_STATUS_SETSID_ERR;
  432         }
  433     }
  434     engine->pid = getpid();
  435     /* write pidfile */
  436     if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
  437         if (engine->daemonize) {
  438             ods_writeln(pipefd[1], "Unable to write pid file");
  439             write(pipefd[1], "\0", 1);
  440             close(pipefd[1]);
  441         }
  442         return ODS_STATUS_WRITE_PIDFILE_ERR;
  443     }
  444     /* setup done */
  445     ods_log_verbose("[%s] running as pid %lu", engine_str,
  446         (unsigned long) engine->pid);
  447     /* catch signals */
  448     action.sa_handler = (void (*)(int))signal_handler;
  449     sigfillset(&action.sa_mask);
  450     action.sa_flags = 0;
  451     sigaction(SIGTERM, &action, NULL);
  452     sigaction(SIGHUP, &action, NULL);
  453     sigaction(SIGINT, &action, NULL);
  454     sigaction(SIGILL, &action, NULL);
  455     sigaction(SIGUSR1, &action, NULL);
  456     sigaction(SIGALRM, &action, NULL);
  457     sigaction(SIGCHLD, &action, NULL);
  458     action.sa_handler = SIG_IGN;
  459     sigaction(SIGPIPE, &action, NULL);
  460     /* create workers/drudgers */
  461     engine_create_workers(engine);
  462     /* start cmd/dns/xfr handlers */
  463     engine_start_cmdhandler(engine);
  464     engine_start_dnshandler(engine);
  465     engine_start_xfrhandler(engine);
  466     tsig_handler_init();
  467     if (engine->daemonize) {
  468         write(pipefd[1], "\1", 1);
  469         close(pipefd[1]);
  470     }
  471     return ODS_STATUS_OK;
  472 }
  473 
  474 
  475 /**
  476  * Run engine, run!.
  477  *
  478  */
  479 static void
  480 engine_run(engine_type* engine)
  481 {
  482     if (!engine) {
  483         return;
  484     }
  485     engine_start_workers(engine);
  486 
  487     while (!engine->need_to_exit && !engine->need_to_reload) {
  488         /* We must use locking here to avoid race conditions. We want
  489          * to sleep indefinitely and want to wake up on signal. This
  490          * is to make sure we never mis the signal. */
  491         pthread_mutex_lock(&engine->signal_lock);
  492         if (!engine->need_to_exit && !engine->need_to_reload) {
  493             /* TODO: this silly. We should be handling the commandhandler
  494              * connections. No reason to spawn that as a thread.
  495              * Also it would be easier to wake up the command hander
  496              * as signals will reach it if it is the main thread! */
  497             ods_log_debug("[%s] taking a break", engine_str);
  498             pthread_cond_wait(&engine->signal_cond, &engine->signal_lock);
  499         }
  500         pthread_mutex_unlock(&engine->signal_lock);
  501     }
  502     ods_log_debug("[%s] signer halted", engine_str);
  503     engine_stop_threads(engine);
  504 }
  505 
  506 
  507 /**
  508  * Parse notify command.
  509  *
  510  */
  511 static void
  512 set_notify_ns(zone_type* zone, const char* cmd)
  513 {
  514     const char* str = NULL;
  515     const char* str2 = NULL;
  516     char* token = NULL;
  517     ods_log_assert(cmd);
  518     ods_log_assert(zone);
  519     ods_log_assert(zone->name);
  520     ods_log_assert(zone->adoutbound);
  521     if (zone->adoutbound->type == ADAPTER_FILE) {
  522         str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
  523         if (!str) {
  524             ods_log_error("[%s] unable to set notify ns: replace zonefile failed",
  525                 engine_str);
  526         }
  527         str2 = ods_replace(str, "%zone", zone->name);
  528         free((void*)str);
  529     } else {
  530         str2 = ods_replace(cmd, "%zone", zone->name);
  531     }
  532     if (str2) {
  533         ods_str_trim((char*) str2, 1);
  534         str = str2;
  535         if (*str) {
  536             token = NULL;
  537             while ((token = strtok((char*) str, " "))) {
  538                 if (*token) {
  539                     ods_str_list_add(&zone->notify_args, token);
  540                 }
  541                 str = NULL;
  542             }
  543         }
  544         zone->notify_command = (char*) str2;
  545         zone->notify_ns = zone->notify_args[0];
  546         ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
  547     } else {
  548         ods_log_error("[%s] unable to set notify ns: replace zone failed",
  549             engine_str);
  550     }
  551 }
  552 
  553 
  554 /**
  555  * Update DNS configuration for zone.
  556  *
  557  */
  558 static int
  559 dnsconfig_zone(engine_type* engine, zone_type* zone)
  560 {
  561     int numdns = 0;
  562     ods_log_assert(engine);
  563     ods_log_assert(engine->xfrhandler);
  564     ods_log_assert(engine->xfrhandler->netio);
  565     ods_log_assert(zone);
  566     ods_log_assert(zone->adinbound);
  567     ods_log_assert(zone->adoutbound);
  568     ods_log_assert(zone->name);
  569 
  570     if (zone->adinbound->type == ADAPTER_DNS) {
  571         /* zone transfer handler */
  572         if (!zone->xfrd) {
  573             ods_log_debug("[%s] add transfer handler for zone %s",
  574                 engine_str, zone->name);
  575             zone->xfrd = xfrd_create((void*) engine->xfrhandler,
  576                 (void*) zone);
  577             ods_log_assert(zone->xfrd);
  578             netio_add_handler(engine->xfrhandler->netio,
  579                 &zone->xfrd->handler);
  580         } else if (!zone->xfrd->serial_disk_acquired) {
  581             xfrd_set_timer_now(zone->xfrd);
  582         }
  583         numdns++;
  584     } else if (zone->xfrd) {
  585         netio_remove_handler(engine->xfrhandler->netio,
  586             &zone->xfrd->handler);
  587         xfrd_cleanup(zone->xfrd, 0);
  588         zone->xfrd = NULL;
  589     }
  590     if (zone->adoutbound->type == ADAPTER_DNS) {
  591         /* notify handler */
  592         if (!zone->notify) {
  593             ods_log_debug("[%s] add notify handler for zone %s",
  594                 engine_str, zone->name);
  595             zone->notify = notify_create((void*) engine->xfrhandler,
  596                 (void*) zone);
  597             ods_log_assert(zone->notify);
  598             netio_add_handler(engine->xfrhandler->netio,
  599                 &zone->notify->handler);
  600         }
  601         numdns++;
  602     } else if (zone->notify) {
  603         netio_remove_handler(engine->xfrhandler->netio,
  604             &zone->notify->handler);
  605         notify_cleanup(zone->notify);
  606         zone->notify = NULL;
  607     }
  608     return numdns;
  609 }
  610 
  611 
  612 /**
  613  * Update zones.
  614  *
  615  */
  616 void
  617 engine_update_zones(engine_type* engine, ods_status zl_changed)
  618 {
  619     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
  620     zone_type* zone = NULL;
  621     ods_status status = ODS_STATUS_OK;
  622     unsigned wake_up = 0;
  623     int warnings = 0;
  624 
  625     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
  626         return;
  627     }
  628 
  629     ods_log_debug("[%s] commit zone list changes", engine_str);
  630     pthread_mutex_lock(&engine->zonelist->zl_lock);
  631     node = ldns_rbtree_first(engine->zonelist->zones);
  632     while (node && node != LDNS_RBTREE_NULL) {
  633         zone = (zone_type*) node->data;
  634 
  635         if (zone->zl_status == ZONE_ZL_REMOVED) {
  636             node = ldns_rbtree_next(node);
  637             pthread_mutex_lock(&zone->zone_lock);
  638             zonelist_del_zone(engine->zonelist, zone);
  639             schedule_unscheduletask(engine->taskq, schedule_WHATEVER, zone->name);
  640             pthread_mutex_unlock(&zone->zone_lock);
  641             netio_remove_handler(engine->xfrhandler->netio,
  642                 &zone->xfrd->handler);
  643             zone_cleanup(zone);
  644             zone = NULL;
  645             continue;
  646         } else if (zone->zl_status == ZONE_ZL_ADDED) {
  647             pthread_mutex_lock(&zone->zone_lock);
  648             /* set notify nameserver command */
  649             if (engine->config->notify_command && !zone->notify_ns) {
  650                 set_notify_ns(zone, engine->config->notify_command);
  651             }
  652             pthread_mutex_unlock(&zone->zone_lock);
  653         }
  654         /* load adapter config */
  655         status = adapter_load_config(zone->adinbound);
  656         if (status != ODS_STATUS_OK) {
  657             ods_log_error("[%s] unable to load config for inbound adapter "
  658                 "for zone %s: %s", engine_str, zone->name,
  659                 ods_status2str(status));
  660         }
  661         status = adapter_load_config(zone->adoutbound);
  662         if (status != ODS_STATUS_OK) {
  663             ods_log_error("[%s] unable to load config for outbound adapter "
  664                 "for zone %s: %s", engine_str, zone->name,
  665                 ods_status2str(status));
  666         }
  667         /* for dns adapters */
  668         warnings += dnsconfig_zone(engine, zone);
  669 
  670         if (zone->zl_status == ZONE_ZL_ADDED) {
  671             schedule_scheduletask(engine->taskq, TASK_SIGNCONF, zone->name, zone, &zone->zone_lock, 0);
  672         } else if (zl_changed == ODS_STATUS_OK) {
  673             schedule_scheduletask(engine->taskq, TASK_FORCESIGNCONF, zone->name, zone, &zone->zone_lock, 0);
  674         }
  675         if (status != ODS_STATUS_OK) {
  676             ods_log_crit("[%s] unable to schedule task for zone %s: %s",
  677                 engine_str, zone->name, ods_status2str(status));
  678         } else {
  679             wake_up = 1;
  680             zone->zl_status = ZONE_ZL_OK;
  681         }
  682         node = ldns_rbtree_next(node);
  683     }
  684     pthread_mutex_unlock(&engine->zonelist->zl_lock);
  685     if (engine->dnshandler) {
  686         ods_log_debug("[%s] forward notify for all zones", engine_str);
  687         dnshandler_fwd_notify(engine->dnshandler,
  688             (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
  689     } else if (warnings) {
  690         ods_log_warning("[%s] no dnshandler/listener configured, but zones "
  691          "are configured with dns adapters: notify and zone transfer "
  692          "requests will not work properly", engine_str);
  693     }
  694     if (wake_up) {
  695         engine_wakeup_workers(engine);
  696     }
  697 }
  698 
  699 
  700 /**
  701  * Try to recover from the backup files.
  702  *
  703  */
  704 static ods_status
  705 engine_recover(engine_type* engine)
  706 {
  707     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
  708     zone_type* zone = NULL;
  709     ods_status status = ODS_STATUS_OK;
  710     ods_status result = ODS_STATUS_UNCHANGED;
  711 
  712     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
  713         ods_log_error("[%s] cannot recover zones: no engine or zonelist",
  714             engine_str);
  715         return ODS_STATUS_ERR; /* no need to update zones */
  716     }
  717     ods_log_assert(engine);
  718     ods_log_assert(engine->zonelist);
  719     ods_log_assert(engine->zonelist->zones);
  720 
  721     pthread_mutex_lock(&engine->zonelist->zl_lock);
  722     /* [LOCK] zonelist */
  723     node = ldns_rbtree_first(engine->zonelist->zones);
  724     while (node && node != LDNS_RBTREE_NULL) {
  725         zone = (zone_type*) node->data;
  726 
  727         ods_log_assert(zone->zl_status == ZONE_ZL_ADDED);
  728         pthread_mutex_lock(&zone->zone_lock);
  729         status = zone_recover2(engine, zone);
  730         if (status == ODS_STATUS_OK) {
  731             ods_log_assert(zone->db);
  732             ods_log_assert(zone->signconf);
  733             /* notify nameserver */
  734             if (engine->config->notify_command && !zone->notify_ns) {
  735                 set_notify_ns(zone, engine->config->notify_command);
  736             }
  737             if (status != ODS_STATUS_OK) {
  738                 ods_log_crit("[%s] unable to schedule task for zone %s: %s",
  739                     engine_str, zone->name, ods_status2str(status));
  740                 result = ODS_STATUS_OK; /* will trigger update zones */
  741             } else {
  742                 ods_log_debug("[%s] recovered zone %s", engine_str,
  743                     zone->name);
  744                 /* recovery done */
  745                 zone->zl_status = ZONE_ZL_OK;
  746             }
  747         } else {
  748             if (status != ODS_STATUS_UNCHANGED) {
  749                 ods_log_warning("[%s] unable to recover zone %s from backup,"
  750                 " performing full sign", engine_str, zone->name);
  751             }
  752             result = ODS_STATUS_OK; /* will trigger update zones */
  753         }
  754         pthread_mutex_unlock(&zone->zone_lock);
  755         node = ldns_rbtree_next(node);
  756     }
  757     /* [UNLOCK] zonelist */
  758     pthread_mutex_unlock(&engine->zonelist->zl_lock);
  759     return result;
  760 }
  761 
  762 
  763 /**
  764  * Start engine.
  765  *
  766  */
  767 int
  768 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize, int info)
  769 {
  770     ods_status zl_changed = ODS_STATUS_UNCHANGED;
  771     ods_status status = ODS_STATUS_OK;
  772 
  773     engine = engine_create();
  774     if (!engine) {
  775         ods_fatal_exit("[%s] create failed", engine_str);
  776         return 1;
  777     }
  778     engine->daemonize = daemonize;
  779 
  780     /* config */
  781     engine->config = engine_config(cfgfile, cmdline_verbosity);
  782     status = engine_config_check(engine->config);
  783     if (status != ODS_STATUS_OK) {
  784         ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
  785         goto earlyexit;
  786     }
  787     if (info) {
  788         engine_config_print(stdout, engine->config); /* for debugging */
  789         goto earlyexit;
  790     }
  791     /* check pidfile */
  792     if (!util_check_pidfile(engine->config->pid_filename)) {
  793         exit(1);
  794     }
  795     /* setup */
  796     status = engine_setup();
  797     if (status != ODS_STATUS_OK) {
  798         ods_log_error("[%s] setup failed: %s", engine_str,
  799             ods_status2str(status));
  800         goto earlyexit;
  801     }
  802 
  803     /* run */
  804     while (engine->need_to_exit == 0) {
  805         /* update zone list */
  806         pthread_mutex_lock(&engine->zonelist->zl_lock);
  807         zl_changed = zonelist_update(engine->zonelist,
  808             engine->config->zonelist_filename);
  809         engine->zonelist->just_removed = 0;
  810         engine->zonelist->just_added = 0;
  811         engine->zonelist->just_updated = 0;
  812         pthread_mutex_unlock(&engine->zonelist->zl_lock);
  813         /* start/reload */
  814         if (engine->need_to_reload) {
  815             ods_log_info("[%s] signer reloading", engine_str);
  816             engine->need_to_reload = 0;
  817         } else {
  818             ods_log_info("[%s] signer started (version %s), pid %u",
  819                 engine_str, PACKAGE_VERSION, engine->pid);
  820             if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
  821                 char* error =  hsm_get_error(NULL);
  822                 if (error != NULL) {
  823                     ods_log_error("[%s] %s", "hsm", error);
  824                     free(error);
  825                 }
  826                 ods_log_error("[%s] opening hsm failed (for engine recover)", engine_str);
  827                 break;
  828             }
  829             zl_changed = engine_recover(engine);
  830             hsm_close();
  831         }
  832         if (zl_changed == ODS_STATUS_OK ||
  833             zl_changed == ODS_STATUS_UNCHANGED) {
  834             engine_update_zones(engine, zl_changed);
  835         }
  836         if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
  837             char* error =  hsm_get_error(NULL);
  838             if (error != NULL) {
  839                 ods_log_error("[%s] %s", "hsm", error);
  840                 free(error);
  841             }
  842             ods_log_error("[%s] opening hsm failed (for engine run)", engine_str);
  843             break;
  844         }
  845         engine_run(engine);
  846         hsm_close();
  847     }
  848 
  849     /* shutdown */
  850     ods_log_info("[%s] signer shutdown", engine_str);
  851     cmdhandler_stop(engine->cmdhandler);
  852     engine_stop_xfrhandler(engine);
  853     engine_stop_dnshandler(engine);
  854 
  855 earlyexit:
  856     if (engine && engine->config) {
  857         if (engine->config->pid_filename) {
  858             (void)unlink(engine->config->pid_filename);
  859         }
  860         if (engine->config->clisock_filename) {
  861             (void)unlink(engine->config->clisock_filename);
  862         }
  863     }
  864     tsig_handler_cleanup();
  865     engine_cleanup(engine);
  866     engine = NULL;
  867 
  868     return 1;
  869 }
  870 
  871 
  872 /**
  873  * Clean up engine.
  874  *
  875  */
  876 void
  877 engine_cleanup(engine_type* engine)
  878 {
  879     int i;
  880     int numTotalWorkers;
  881 
  882     if (!engine) {
  883         return;
  884     }
  885     if (engine->config) {
  886         numTotalWorkers = engine->config->num_worker_threads + engine->config->num_signer_threads;
  887         if (engine->workers) {
  888             for (i=0; i < (size_t) numTotalWorkers; i++) {
  889                 worker_cleanup(engine->workers[i]);
  890             }
  891             free(engine->workers);
  892         }
  893         zonelist_cleanup(engine->zonelist);
  894         schedule_cleanup(engine->taskq);
  895         cmdhandler_cleanup(engine->cmdhandler);
  896         dnshandler_cleanup(engine->dnshandler);
  897         xfrhandler_cleanup(engine->xfrhandler);
  898         engine_config_cleanup(engine->config);
  899         pthread_mutex_destroy(&engine->signal_lock);
  900         pthread_cond_destroy(&engine->signal_cond);
  901     }
  902     free(engine);
  903 }