OpenDNSSEC-signer 1.3.0
|
00001 /* 00002 * $Id: engine.c 5320 2011-07-12 10:42:26Z jakob $ 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/cfg.h" 00036 #include "daemon/cmdhandler.h" 00037 #include "daemon/engine.h" 00038 #include "daemon/signal.h" 00039 #include "daemon/worker.h" 00040 #include "scheduler/schedule.h" 00041 #include "scheduler/task.h" 00042 #include "shared/allocator.h" 00043 #include "shared/file.h" 00044 #include "shared/locks.h" 00045 #include "shared/log.h" 00046 #include "shared/privdrop.h" 00047 #include "shared/status.h" 00048 #include "shared/util.h" 00049 #include "signer/zone.h" 00050 #include "signer/zonelist.h" 00051 #include "tools/zone_fetcher.h" 00052 00053 #include <errno.h> 00054 #include <libhsm.h> 00055 #include <libxml/parser.h> 00056 #include <signal.h> 00057 #include <stdio.h> 00058 #include <stdlib.h> 00059 #include <string.h> 00060 #include <strings.h> 00061 #include <sys/socket.h> 00062 #include <sys/types.h> 00063 #include <sys/un.h> 00064 #include <time.h> 00065 #include <unistd.h> 00066 00067 static const char* engine_str = "engine"; 00068 00069 00074 static engine_type* 00075 engine_create(void) 00076 { 00077 engine_type* engine; 00078 allocator_type* allocator = allocator_create(malloc, free); 00079 if (!allocator) { 00080 return NULL; 00081 } 00082 engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type)); 00083 if (!engine) { 00084 allocator_cleanup(allocator); 00085 return NULL; 00086 } 00087 engine->allocator = allocator; 00088 engine->config = NULL; 00089 engine->workers = NULL; 00090 engine->drudgers = NULL; 00091 engine->cmdhandler = NULL; 00092 engine->cmdhandler_done = 0; 00093 engine->pid = -1; 00094 engine->zfpid = -1; 00095 engine->uid = -1; 00096 engine->gid = -1; 00097 engine->daemonize = 0; 00098 engine->need_to_exit = 0; 00099 engine->need_to_reload = 0; 00100 00101 lock_basic_init(&engine->signal_lock); 00102 lock_basic_set(&engine->signal_cond); 00103 lock_basic_lock(&engine->signal_lock); 00104 engine->signal = SIGNAL_INIT; 00105 lock_basic_unlock(&engine->signal_lock); 00106 00107 engine->zonelist = zonelist_create(engine->allocator); 00108 if (!engine->zonelist) { 00109 engine_cleanup(engine); 00110 return NULL; 00111 } 00112 engine->taskq = schedule_create(engine->allocator); 00113 if (!engine->taskq) { 00114 engine_cleanup(engine); 00115 return NULL; 00116 } 00117 engine->signq = fifoq_create(engine->allocator); 00118 if (!engine->signq) { 00119 engine_cleanup(engine); 00120 return NULL; 00121 } 00122 return engine; 00123 } 00124 00125 00130 static void* 00131 cmdhandler_thread_start(void* arg) 00132 { 00133 cmdhandler_type* cmd = (cmdhandler_type*) arg; 00134 ods_thread_blocksigs(); 00135 cmdhandler_start(cmd); 00136 return NULL; 00137 } 00138 static void 00139 engine_start_cmdhandler(engine_type* engine) 00140 { 00141 ods_log_assert(engine); 00142 ods_log_debug("[%s] start command handler", engine_str); 00143 engine->cmdhandler->engine = engine; 00144 ods_thread_create(&engine->cmdhandler->thread_id, 00145 cmdhandler_thread_start, engine->cmdhandler); 00146 return; 00147 } 00152 static int 00153 self_pipe_trick(engine_type* engine) 00154 { 00155 int sockfd, ret; 00156 struct sockaddr_un servaddr; 00157 const char* servsock_filename = ODS_SE_SOCKFILE; 00158 00159 ods_log_assert(engine); 00160 ods_log_assert(engine->cmdhandler); 00161 00162 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 00163 if (sockfd <= 0) { 00164 ods_log_error("[%s] cannot connect to command handler: " 00165 "socket() failed: %s\n", engine_str, strerror(errno)); 00166 return 1; 00167 } else { 00168 bzero(&servaddr, sizeof(servaddr)); 00169 servaddr.sun_family = AF_UNIX; 00170 strncpy(servaddr.sun_path, servsock_filename, 00171 sizeof(servaddr.sun_path) - 1); 00172 00173 ret = connect(sockfd, (const struct sockaddr*) &servaddr, 00174 sizeof(servaddr)); 00175 if (ret != 0) { 00176 ods_log_error("[%s] cannot connect to command handler: " 00177 "connect() failed: %s\n", engine_str, strerror(errno)); 00178 close(sockfd); 00179 return 1; 00180 } else { 00181 /* self-pipe trick */ 00182 ods_writen(sockfd, "", 1); 00183 close(sockfd); 00184 } 00185 } 00186 return 0; 00187 } 00192 static void 00193 engine_stop_cmdhandler(engine_type* engine) 00194 { 00195 ods_log_assert(engine); 00196 if (!engine->cmdhandler) { 00197 return; 00198 } 00199 ods_log_debug("[%s] stop command handler", engine_str); 00200 engine->cmdhandler->need_to_exit = 1; 00201 if (self_pipe_trick(engine) == 0) { 00202 while (!engine->cmdhandler_done) { 00203 ods_log_debug("[%s] waiting for command handler to exit...", 00204 engine_str); 00205 sleep(1); 00206 } 00207 } else { 00208 ods_log_error("[%s] command handler self pipe trick failed, " 00209 "unclean shutdown", engine_str); 00210 } 00211 return; 00212 } 00213 00214 00219 static ods_status 00220 engine_privdrop(engine_type* engine) 00221 { 00222 ods_status status = ODS_STATUS_OK; 00223 uid_t uid = -1; 00224 gid_t gid = -1; 00225 00226 ods_log_assert(engine); 00227 ods_log_assert(engine->config); 00228 ods_log_debug("[%s] drop privileges", engine_str); 00229 00230 if (engine->config->username && engine->config->group) { 00231 ods_log_verbose("[%s] drop privileges to user %s, group %s", 00232 engine_str, engine->config->username, engine->config->group); 00233 } else if (engine->config->username) { 00234 ods_log_verbose("[%s] drop privileges to user %s", engine_str, 00235 engine->config->username); 00236 } else if (engine->config->group) { 00237 ods_log_verbose("[%s] drop privileges to group %s", engine_str, 00238 engine->config->group); 00239 } 00240 if (engine->config->chroot) { 00241 ods_log_verbose("[%s] chroot to %s", engine_str, 00242 engine->config->chroot); 00243 } 00244 status = privdrop(engine->config->username, engine->config->group, 00245 engine->config->chroot, &uid, &gid); 00246 engine->uid = uid; 00247 engine->gid = gid; 00248 privclose(engine->config->username, engine->config->group); 00249 return status; 00250 } 00251 00252 00257 static void 00258 engine_create_workers(engine_type* engine) 00259 { 00260 size_t i = 0; 00261 ods_log_assert(engine); 00262 ods_log_assert(engine->config); 00263 ods_log_assert(engine->allocator); 00264 engine->workers = (worker_type**) allocator_alloc(engine->allocator, 00265 ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*)); 00266 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00267 engine->workers[i] = worker_create(engine->allocator, i, 00268 WORKER_WORKER); 00269 } 00270 return; 00271 } 00272 static void 00273 engine_create_drudgers(engine_type* engine) 00274 { 00275 size_t i = 0; 00276 ods_log_assert(engine); 00277 ods_log_assert(engine->config); 00278 ods_log_assert(engine->allocator); 00279 engine->drudgers = (worker_type**) allocator_alloc(engine->allocator, 00280 ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*)); 00281 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00282 engine->drudgers[i] = worker_create(engine->allocator, i, 00283 WORKER_DRUDGER); 00284 } 00285 return; 00286 } 00287 static void* 00288 worker_thread_start(void* arg) 00289 { 00290 worker_type* worker = (worker_type*) arg; 00291 ods_thread_blocksigs(); 00292 worker_start(worker); 00293 return NULL; 00294 } 00295 static void 00296 engine_start_workers(engine_type* engine) 00297 { 00298 size_t i = 0; 00299 00300 ods_log_assert(engine); 00301 ods_log_assert(engine->config); 00302 ods_log_debug("[%s] start workers", engine_str); 00303 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00304 engine->workers[i]->need_to_exit = 0; 00305 engine->workers[i]->engine = (struct engine_struct*) engine; 00306 ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start, 00307 engine->workers[i]); 00308 } 00309 return; 00310 } 00311 static void 00312 engine_start_drudgers(engine_type* engine) 00313 { 00314 size_t i = 0; 00315 00316 ods_log_assert(engine); 00317 ods_log_assert(engine->config); 00318 ods_log_debug("[%s] start drudgers", engine_str); 00319 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00320 engine->drudgers[i]->need_to_exit = 0; 00321 engine->drudgers[i]->engine = (struct engine_struct*) engine; 00322 ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start, 00323 engine->drudgers[i]); 00324 } 00325 return; 00326 } 00327 static void 00328 engine_stop_workers(engine_type* engine) 00329 { 00330 size_t i = 0; 00331 00332 ods_log_assert(engine); 00333 ods_log_assert(engine->config); 00334 ods_log_debug("[%s] stop workers", engine_str); 00335 /* tell them to exit and wake up sleepyheads */ 00336 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00337 engine->workers[i]->need_to_exit = 1; 00338 worker_wakeup(engine->workers[i]); 00339 } 00340 /* head count */ 00341 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00342 ods_log_debug("[%s] join worker %i", engine_str, i+1); 00343 ods_thread_join(engine->workers[i]->thread_id); 00344 engine->workers[i]->engine = NULL; 00345 } 00346 return; 00347 } 00348 static void 00349 engine_stop_drudgers(engine_type* engine) 00350 { 00351 size_t i = 0; 00352 00353 ods_log_assert(engine); 00354 ods_log_assert(engine->config); 00355 ods_log_debug("[%s] stop drudgers", engine_str); 00356 /* tell them to exit and wake up sleepyheads */ 00357 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00358 engine->drudgers[i]->need_to_exit = 1; 00359 } 00360 worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold); 00361 00362 /* head count */ 00363 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00364 ods_log_debug("[%s] join drudger %i", engine_str, i+1); 00365 ods_thread_join(engine->drudgers[i]->thread_id); 00366 engine->drudgers[i]->engine = NULL; 00367 } 00368 return; 00369 } 00370 00371 00376 void 00377 engine_wakeup_workers(engine_type* engine) 00378 { 00379 size_t i = 0; 00380 00381 ods_log_assert(engine); 00382 ods_log_assert(engine->config); 00383 ods_log_debug("[%s] wake up workers", engine_str); 00384 /* wake up sleepyheads */ 00385 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00386 worker_wakeup(engine->workers[i]); 00387 } 00388 return; 00389 } 00390 00391 00396 static int 00397 start_zonefetcher(engine_type* engine) 00398 { 00399 pid_t zfpid = 0; 00400 int result = 0; 00401 char* zf_filename = NULL; 00402 char* zl_filename = NULL; 00403 char* log_filename = NULL; 00404 char* grp = NULL; 00405 char* usr = NULL; 00406 char* chrt = NULL; 00407 int use_syslog = 0; 00408 int verbosity = 0; 00409 00410 ods_log_assert(engine); 00411 ods_log_assert(engine->config); 00412 00413 if (!engine->config->zonefetch_filename) { 00414 /* zone fetcher disabled */ 00415 return 0; 00416 } 00417 00418 switch ((zfpid = fork())) { 00419 case -1: /* error */ 00420 ods_log_error("failed to fork zone fetcher: %s", 00421 strerror(errno)); 00422 return 1; 00423 case 0: /* child */ 00424 break; 00425 default: /* parent */ 00426 engine->zfpid = zfpid; 00427 return 0; 00428 } 00429 00430 if (setsid() == -1) { 00431 ods_log_error("failed to setsid zone fetcher: %s", 00432 strerror(errno)); 00433 return 1; 00434 } 00435 00436 hsm_close(); 00437 ods_log_verbose("zone fetcher running as pid %lu", 00438 (unsigned long) getpid()); 00439 00440 if (engine->config->zonefetch_filename) { 00441 zf_filename = strdup(engine->config->zonefetch_filename); 00442 } 00443 if (engine->config->zonelist_filename) { 00444 zl_filename = strdup(engine->config->zonelist_filename); 00445 } 00446 if (engine->config->group) { 00447 grp = strdup(engine->config->group); 00448 } 00449 if (engine->config->username) { 00450 usr = strdup(engine->config->username); 00451 } 00452 if (engine->config->chroot) { 00453 chrt = strdup(engine->config->chroot); 00454 } 00455 if (engine->config->log_filename) { 00456 log_filename = strdup(engine->config->log_filename); 00457 } 00458 use_syslog = engine->config->use_syslog; 00459 verbosity = engine->config->verbosity; 00460 00461 result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr, 00462 chrt, log_filename, use_syslog, verbosity); 00463 00464 ods_log_verbose("zone fetcher done", result); 00465 if (zf_filename) { free((void*)zf_filename); } 00466 if (zl_filename) { free((void*)zl_filename); } 00467 if (grp) { free((void*)grp); } 00468 if (usr) { free((void*)usr); } 00469 if (chrt) { free((void*)chrt); } 00470 if (log_filename) { free((void*)log_filename); } 00471 00472 engine_cleanup(engine); 00473 engine = NULL; 00474 ods_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 ods_log_assert(engine); 00494 ods_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 ods_log_error("cannot reload zone fetcher: %s", 00501 strerror(errno)); 00502 } else { 00503 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid); 00504 } 00505 } else { 00506 ods_log_error("cannot reload zone fetcher: process id unknown"); 00507 } 00508 } 00509 return; 00510 } 00511 00512 00517 static void 00518 stop_zonefetcher(engine_type* engine) 00519 { 00520 int result = 0; 00521 00522 ods_log_assert(engine); 00523 ods_log_assert(engine->config); 00524 00525 if (engine->config->zonefetch_filename) { 00526 if (engine->zfpid > 0) { 00527 result = kill(engine->zfpid, SIGTERM); 00528 if (result == -1) { 00529 ods_log_error("cannot stop zone fetcher: %s", strerror(errno)); 00530 } else { 00531 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid); 00532 } 00533 engine->zfpid = -1; 00534 } else { 00535 ods_log_error("cannot stop zone fetcher: process id unknown"); 00536 } 00537 } 00538 return; 00539 } 00540 00541 00546 static ods_status 00547 engine_init_adapters(engine_type* engine) 00548 { 00549 size_t i = 0; 00550 ods_status status = ODS_STATUS_OK; 00551 00552 ods_log_assert(engine); 00553 ods_log_assert(engine->config); 00554 ods_log_debug("[%s] initialize adapters", engine_str); 00555 for (i=0; i < (size_t) engine->config->num_adapters; i++) { 00556 status = adapter_init(engine->config->adapters[i]); 00557 if (status != ODS_STATUS_OK) { 00558 return status; 00559 } 00560 } 00561 return status; 00562 } 00563 00564 00569 static ods_status 00570 engine_setup(engine_type* engine) 00571 { 00572 struct sigaction action; 00573 int result = 0; 00574 ods_status status = ODS_STATUS_OK; 00575 00576 ods_log_debug("[%s] signer setup", engine_str); 00577 if (!engine || !engine->config) { 00578 return ODS_STATUS_ASSERT_ERR; 00579 } 00580 00581 /* create command handler (before chowning socket file) */ 00582 engine->cmdhandler = cmdhandler_create(engine->allocator, 00583 engine->config->clisock_filename); 00584 if (!engine->cmdhandler) { 00585 ods_log_error("[%s] create command handler to %s failed", 00586 engine_str, engine->config->clisock_filename); 00587 return ODS_STATUS_CMDHANDLER_ERR; 00588 } 00589 00590 /* fork of fetcher */ 00591 if (start_zonefetcher(engine) != 0) { 00592 ods_log_error("[%s] cannot start zonefetcher", engine_str); 00593 return ODS_STATUS_ERR; 00594 } 00595 00596 /* initialize adapters */ 00597 status = engine_init_adapters(engine); 00598 if (status != ODS_STATUS_OK) { 00599 ods_log_error("[%s] initializing adapters failed", engine_str); 00600 return status; 00601 } 00602 00603 /* privdrop */ 00604 engine->uid = privuid(engine->config->username); 00605 engine->gid = privgid(engine->config->group); 00606 /* TODO: does piddir exists? */ 00607 /* remove the chown stuff: piddir? */ 00608 ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1); 00609 ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0); 00610 ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0); 00611 if (engine->config->log_filename && !engine->config->use_syslog) { 00612 ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0); 00613 } 00614 if (engine->config->working_dir && 00615 chdir(engine->config->working_dir) != 0) { 00616 ods_log_error("[%s] chdir to %s failed: %s", engine_str, 00617 engine->config->working_dir, strerror(errno)); 00618 return ODS_STATUS_CHDIR_ERR; 00619 } 00620 if (engine_privdrop(engine) != ODS_STATUS_OK) { 00621 ods_log_error("[%s] unable to drop privileges", engine_str); 00622 return ODS_STATUS_PRIVDROP_ERR; 00623 } 00624 00625 /* daemonize */ 00626 if (engine->daemonize) { 00627 switch ((engine->pid = fork())) { 00628 case -1: /* error */ 00629 ods_log_error("[%s] unable to fork daemon: %s", 00630 engine_str, strerror(errno)); 00631 return ODS_STATUS_FORK_ERR; 00632 case 0: /* child */ 00633 break; 00634 default: /* parent */ 00635 engine_cleanup(engine); 00636 engine = NULL; 00637 xmlCleanupParser(); 00638 xmlCleanupGlobals(); 00639 xmlCleanupThreads(); 00640 exit(0); 00641 } 00642 if (setsid() == -1) { 00643 ods_log_error("[%s] unable to setsid daemon (%s)", 00644 engine_str, strerror(errno)); 00645 return ODS_STATUS_SETSID_ERR; 00646 } 00647 } 00648 engine->pid = getpid(); 00649 ods_log_verbose("[%s] running as pid %lu", engine_str, 00650 (unsigned long) engine->pid); 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 */ /* LEAK */ 00661 result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL); 00662 if (result != HSM_OK) { 00663 ods_log_error("[%s] error initializing libhsm (errno %i)", 00664 engine_str, result); 00665 return ODS_STATUS_HSM_ERR; 00666 } 00667 00668 /* create workers */ 00669 engine_create_workers(engine); 00670 engine_create_drudgers(engine); 00671 00672 /* start command handler */ 00673 engine_start_cmdhandler(engine); 00674 00675 /* write pidfile */ 00676 if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) { 00677 hsm_close(); 00678 ods_log_error("[%s] unable to write pid file", engine_str); 00679 return ODS_STATUS_WRITE_PIDFILE_ERR; 00680 } 00681 00682 return ODS_STATUS_OK; 00683 } 00684 00685 00690 static int 00691 engine_all_zones_processed(engine_type* engine) 00692 { 00693 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00694 zone_type* zone = NULL; 00695 00696 ods_log_assert(engine); 00697 ods_log_assert(engine->zonelist); 00698 ods_log_assert(engine->zonelist->zones); 00699 00700 node = ldns_rbtree_first(engine->zonelist->zones); 00701 while (node && node != LDNS_RBTREE_NULL) { 00702 zone = (zone_type*) node->key; 00703 if (!zone->processed) { 00704 return 0; 00705 } 00706 node = ldns_rbtree_next(node); 00707 } 00708 return 1; 00709 } 00710 00711 00716 static void 00717 engine_run(engine_type* engine, int single_run) 00718 { 00719 if (!engine) { 00720 return; 00721 } 00722 ods_log_assert(engine); 00723 00724 engine_start_workers(engine); 00725 engine_start_drudgers(engine); 00726 00727 lock_basic_lock(&engine->signal_lock); 00728 /* [LOCK] signal */ 00729 engine->signal = SIGNAL_RUN; 00730 /* [UNLOCK] signal */ 00731 lock_basic_unlock(&engine->signal_lock); 00732 00733 while (!engine->need_to_exit && !engine->need_to_reload) { 00734 lock_basic_lock(&engine->signal_lock); 00735 /* [LOCK] signal */ 00736 engine->signal = signal_capture(engine->signal); 00737 switch (engine->signal) { 00738 case SIGNAL_RUN: 00739 ods_log_assert(1); 00740 break; 00741 case SIGNAL_RELOAD: 00742 engine->need_to_reload = 1; 00743 break; 00744 case SIGNAL_SHUTDOWN: 00745 engine->need_to_exit = 1; 00746 break; 00747 default: 00748 ods_log_warning("[%s] invalid signal captured: %d, " 00749 "keep running", engine_str, signal); 00750 engine->signal = SIGNAL_RUN; 00751 break; 00752 } 00753 /* [UNLOCK] signal */ 00754 lock_basic_unlock(&engine->signal_lock); 00755 00756 if (single_run) { 00757 engine->need_to_exit = engine_all_zones_processed(engine); 00758 } 00759 00760 lock_basic_lock(&engine->signal_lock); 00761 /* [LOCK] signal */ 00762 if (engine->signal == SIGNAL_RUN && !single_run) { 00763 ods_log_debug("[%s] taking a break", engine_str); 00764 lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600); 00765 } 00766 /* [UNLOCK] signal */ 00767 lock_basic_unlock(&engine->signal_lock); 00768 } 00769 ods_log_debug("[%s] signer halted", engine_str); 00770 engine_stop_drudgers(engine); 00771 engine_stop_workers(engine); 00772 return; 00773 } 00774 00775 00780 static void 00781 set_notify_ns(zone_type* zone, const char* cmd) 00782 { 00783 const char* str = NULL; 00784 const char* str2 = NULL; 00785 00786 ods_log_assert(cmd); 00787 ods_log_assert(zone); 00788 ods_log_assert(zone->name); 00789 ods_log_assert(zone->adoutbound); 00790 00791 if (zone->adoutbound->type == ADAPTER_FILE) { 00792 str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr); 00793 } else { 00794 str = cmd; 00795 } 00796 00797 str2 = ods_replace(str, "%zone", zone->name); 00798 free((void*)str); 00799 zone->notify_ns = (const char*) str2; 00800 ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns); 00801 return; 00802 } 00803 00804 00809 void 00810 engine_update_zones(engine_type* engine) 00811 { 00812 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00813 zone_type* zone = NULL; 00814 zone_type* delzone = NULL; 00815 task_type* task = NULL; 00816 ods_status status = ODS_STATUS_OK; 00817 int wake_up = 0; 00818 time_t now; 00819 00820 if (!engine || !engine->zonelist || !engine->zonelist->zones) { 00821 ods_log_error("[%s] cannot update zones: no engine or zonelist", 00822 engine_str); 00823 return; 00824 } 00825 ods_log_assert(engine); 00826 ods_log_assert(engine->zonelist); 00827 ods_log_assert(engine->zonelist->zones); 00828 00829 now = time_now(); 00830 reload_zonefetcher(engine); 00831 00832 lock_basic_lock(&engine->zonelist->zl_lock); 00833 /* [LOCK] zonelist */ 00834 node = ldns_rbtree_first(engine->zonelist->zones); 00835 while (node && node != LDNS_RBTREE_NULL) { 00836 zone = (zone_type*) node->data; 00837 task = NULL; /* reset task */ 00838 00839 if (zone->tobe_removed) { 00840 node = ldns_rbtree_next(node); 00841 00842 lock_basic_lock(&zone->zone_lock); 00843 /* [LOCK] zone */ 00844 delzone = zonelist_del_zone(engine->zonelist, zone); 00845 if (delzone) { 00846 lock_basic_lock(&engine->taskq->schedule_lock); 00847 /* [LOCK] schedule */ 00848 task = unschedule_task(engine->taskq, 00849 (task_type*) zone->task); 00850 /* [UNLOCK] schedule */ 00851 lock_basic_unlock(&engine->taskq->schedule_lock); 00852 } 00853 task_cleanup(task); 00854 task = NULL; 00855 /* [UNLOCK] zone */ 00856 lock_basic_unlock(&zone->zone_lock); 00857 00858 zone_cleanup(zone); 00859 zone = NULL; 00860 continue; 00861 } else if (zone->just_added) { 00862 00863 lock_basic_lock(&zone->zone_lock); 00864 ods_log_assert(!zone->task); 00865 zone->just_added = 0; 00866 /* notify nameserver */ 00867 if (engine->config->notify_command && !zone->notify_ns) { 00868 set_notify_ns(zone, engine->config->notify_command); 00869 } 00870 /* schedule task */ 00871 task = task_create(TASK_SIGNCONF, now, zone->name, zone); 00872 if (!task) { 00873 ods_log_crit("[%s] failed to create task for zone %s", 00874 engine_str, zone->name); 00875 } else { 00876 lock_basic_lock(&engine->taskq->schedule_lock); 00877 /* [LOCK] schedule */ 00878 status = schedule_task(engine->taskq, task, 0); 00879 /* [UNLOCK] schedule */ 00880 lock_basic_unlock(&engine->taskq->schedule_lock); 00881 wake_up = 1; 00882 } 00883 /* zone fetcher enabled? */ 00884 zone->fetch = (engine->config->zonefetch_filename != NULL); 00885 lock_basic_unlock(&zone->zone_lock); 00886 } else if (zone->just_updated) { 00887 lock_basic_lock(&zone->zone_lock); 00888 ods_log_assert(zone->task); 00889 zone->just_updated = 0; 00890 /* reschedule task */ 00891 lock_basic_lock(&engine->taskq->schedule_lock); 00892 /* [LOCK] schedule */ 00893 task = unschedule_task(engine->taskq, (task_type*) zone->task); 00894 if (task != NULL) { 00895 ods_log_debug("[%s] reschedule task for zone %s", engine_str, 00896 zone->name); 00897 if (task->what != TASK_SIGNCONF) { 00898 task->halted = task->what; 00899 task->interrupt = TASK_SIGNCONF; 00900 } 00901 task->what = TASK_SIGNCONF; 00902 task->when = now; 00903 status = schedule_task(engine->taskq, task, 0); 00904 } else { 00905 /* task now queued, being worked on? */ 00906 ods_log_debug("[%s] worker busy with zone %s, will update " 00907 "signconf as soon as possible", engine_str, zone->name); 00908 task = (task_type*) zone->task; 00909 task->interrupt = TASK_SIGNCONF; 00910 /* task->halted set by worker */ 00911 } 00912 /* [UNLOCK] schedule */ 00913 lock_basic_unlock(&engine->taskq->schedule_lock); 00914 lock_basic_unlock(&zone->zone_lock); 00915 00916 wake_up = 1; 00917 } 00918 00919 zone->task = task; 00920 if (status != ODS_STATUS_OK) { 00921 ods_log_crit("[%s] failed to schedule task for zone %s: %s", 00922 engine_str, zone->name, ods_status2str(status)); 00923 task_cleanup(task); 00924 zone->task = NULL; 00925 } 00926 node = ldns_rbtree_next(node); 00927 } 00928 /* [UNLOCK] zonelist */ 00929 lock_basic_unlock(&engine->zonelist->zl_lock); 00930 00931 if (wake_up) { 00932 engine_wakeup_workers(engine); 00933 } 00934 return; 00935 } 00936 00937 00942 static ods_status 00943 engine_recover(engine_type* engine) 00944 { 00945 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00946 zone_type* zone = NULL; 00947 ods_status status = ODS_STATUS_OK; 00948 ods_status result = ODS_STATUS_UNCHANGED; 00949 00950 if (!engine || !engine->zonelist || !engine->zonelist->zones) { 00951 ods_log_error("[%s] cannot update zones: no engine or zonelist", 00952 engine_str); 00953 return ODS_STATUS_OK; /* will trigger update zones */ 00954 } 00955 ods_log_assert(engine); 00956 ods_log_assert(engine->zonelist); 00957 ods_log_assert(engine->zonelist->zones); 00958 00959 lock_basic_lock(&engine->zonelist->zl_lock); 00960 /* [LOCK] zonelist */ 00961 node = ldns_rbtree_first(engine->zonelist->zones); 00962 while (node && node != LDNS_RBTREE_NULL) { 00963 zone = (zone_type*) node->data; 00964 00965 ods_log_assert(zone->just_added); 00966 status = zone_recover(zone); 00967 if (status == ODS_STATUS_OK) { 00968 ods_log_assert(zone->task); 00969 ods_log_assert(zone->zonedata); 00970 ods_log_assert(zone->signconf); 00971 /* notify nameserver */ 00972 if (engine->config->notify_command && !zone->notify_ns) { 00973 set_notify_ns(zone, engine->config->notify_command); 00974 } 00975 /* zone fetcher enabled? */ 00976 zone->fetch = (engine->config->zonefetch_filename != NULL); 00977 /* schedule task */ 00978 lock_basic_lock(&engine->taskq->schedule_lock); 00979 /* [LOCK] schedule */ 00980 status = schedule_task(engine->taskq, (task_type*) zone->task, 0); 00981 /* [UNLOCK] schedule */ 00982 lock_basic_unlock(&engine->taskq->schedule_lock); 00983 00984 if (status != ODS_STATUS_OK) { 00985 ods_log_crit("[%s] unable to schedule task for zone %s: %s", 00986 engine_str, zone->name, ods_status2str(status)); 00987 task_cleanup((task_type*) zone->task); 00988 zone->task = NULL; 00989 result = ODS_STATUS_OK; /* will trigger update zones */ 00990 } else { 00991 ods_log_verbose("[%s] recovered zone %s", engine_str, 00992 zone->name); 00993 /* recovery done */ 00994 zone->just_added = 0; 00995 } 00996 } else { 00997 if (status != ODS_STATUS_UNCHANGED) { 00998 ods_log_warning("[%s] unable to recover zone %s from backup," 00999 " performing full sign", engine_str, zone->name); 01000 } 01001 result = ODS_STATUS_OK; /* will trigger update zones */ 01002 } 01003 node = ldns_rbtree_next(node); 01004 } 01005 /* [UNLOCK] zonelist */ 01006 lock_basic_unlock(&engine->zonelist->zl_lock); 01007 return result; 01008 } 01009 01010 01015 void 01016 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize, 01017 int info, int single_run) 01018 { 01019 engine_type* engine = NULL; 01020 int use_syslog = 0; 01021 ods_status zl_changed = ODS_STATUS_UNCHANGED; 01022 ods_status status = ODS_STATUS_OK; 01023 int close_hsm = 0; 01024 01025 ods_log_assert(cfgfile); 01026 ods_log_init(NULL, use_syslog, cmdline_verbosity); 01027 ods_log_verbose("[%s] starting signer", engine_str); 01028 01029 /* initialize */ 01030 xmlInitGlobals(); 01031 xmlInitParser(); 01032 xmlInitThreads(); 01033 engine = engine_create(); 01034 if (!engine) { 01035 ods_fatal_exit("[%s] create failed", engine_str); 01036 return; 01037 } 01038 engine->daemonize = daemonize; 01039 01040 /* config */ 01041 engine->config = engine_config(engine->allocator, cfgfile, 01042 cmdline_verbosity); 01043 status = engine_config_check(engine->config); 01044 if (status != ODS_STATUS_OK) { 01045 ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile); 01046 goto earlyexit; 01047 } 01048 if (info) { 01049 engine_config_print(stdout, engine->config); /* for debugging */ 01050 goto earlyexit; 01051 } 01052 01053 /* open log */ 01054 ods_log_init(engine->config->log_filename, engine->config->use_syslog, 01055 engine->config->verbosity); 01056 01057 /* setup */ 01058 tzset(); /* for portability */ 01059 status = engine_setup(engine); 01060 if (status != ODS_STATUS_OK) { 01061 ods_log_error("[%s] setup failed: %s", engine_str, 01062 ods_status2str(status)); 01063 engine->need_to_exit = 1; 01064 if (status != ODS_STATUS_WRITE_PIDFILE_ERR) { 01065 /* command handler had not yet been started */ 01066 engine->cmdhandler_done = 1; 01067 /* hsm has been opened */ 01068 hsm_close(); 01069 } 01070 } else { 01071 /* setup ok, mark hsm open */ 01072 close_hsm = 1; 01073 } 01074 01075 /* run */ 01076 while (engine->need_to_exit == 0) { 01077 /* update zone list */ 01078 lock_basic_lock(&engine->zonelist->zl_lock); 01079 /* [LOCK] zonelist */ 01080 zl_changed = zonelist_update(engine->zonelist, 01081 engine->config->zonelist_filename); 01082 engine->zonelist->just_removed = 0; 01083 engine->zonelist->just_added = 0; 01084 engine->zonelist->just_updated = 0; 01085 /* [UNLOCK] zonelist */ 01086 lock_basic_unlock(&engine->zonelist->zl_lock); 01087 01088 if (engine->need_to_reload) { 01089 ods_log_info("[%s] signer reloading", engine_str); 01090 engine->need_to_reload = 0; 01091 } else { 01092 ods_log_info("[%s] signer started", engine_str); 01093 zl_changed = engine_recover(engine); 01094 } 01095 01096 /* update zones */ 01097 if (zl_changed == ODS_STATUS_OK) { 01098 ods_log_debug("[%s] commit zone list changes", engine_str); 01099 engine_update_zones(engine); 01100 ods_log_debug("[%s] signer configurations updated", engine_str); 01101 zl_changed = ODS_STATUS_UNCHANGED; 01102 } 01103 01104 engine_run(engine, single_run); 01105 } 01106 01107 /* shutdown */ 01108 ods_log_info("[%s] signer shutdown", engine_str); 01109 stop_zonefetcher(engine); 01110 if (close_hsm) { 01111 hsm_close(); 01112 } 01113 if (engine->cmdhandler != NULL) { 01114 engine_stop_cmdhandler(engine); 01115 } 01116 01117 earlyexit: 01118 if (engine && engine->config) { 01119 if (engine->config->pid_filename) { 01120 (void)unlink(engine->config->pid_filename); 01121 } 01122 if (engine->config->clisock_filename) { 01123 (void)unlink(engine->config->clisock_filename); 01124 } 01125 } 01126 engine_cleanup(engine); 01127 engine = NULL; 01128 ods_log_close(); 01129 xmlCleanupParser(); 01130 xmlCleanupGlobals(); 01131 xmlCleanupThreads(); 01132 return; 01133 } 01134 01135 01140 void 01141 engine_cleanup(engine_type* engine) 01142 { 01143 size_t i = 0; 01144 allocator_type* allocator; 01145 cond_basic_type signal_cond; 01146 lock_basic_type signal_lock; 01147 01148 if (!engine) { 01149 return; 01150 } 01151 allocator = engine->allocator; 01152 signal_cond = engine->signal_cond; 01153 signal_lock = engine->signal_lock; 01154 01155 if (engine->workers && engine->config) { 01156 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 01157 worker_cleanup(engine->workers[i]); 01158 } 01159 allocator_deallocate(allocator, (void*) engine->workers); 01160 } 01161 if (engine->drudgers && engine->config) { 01162 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 01163 worker_cleanup(engine->drudgers[i]); 01164 } 01165 allocator_deallocate(allocator, (void*) engine->drudgers); 01166 } 01167 zonelist_cleanup(engine->zonelist); 01168 schedule_cleanup(engine->taskq); 01169 fifoq_cleanup(engine->signq); 01170 cmdhandler_cleanup(engine->cmdhandler); 01171 engine_config_cleanup(engine->config); 01172 allocator_deallocate(allocator, (void*) engine); 01173 01174 lock_basic_destroy(&signal_lock); 01175 lock_basic_off(&signal_cond); 01176 allocator_cleanup(allocator); 01177 return; 01178 }