OpenDNSSEC-signer 1.2.1
|
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 }