OpenDNSSEC-signer
1.3.4
|
00001 /* 00002 * $Id: engine.c 5656 2011-09-30 06:45:25Z matthijs $ 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 ods_log_verbose("zone fetcher running as pid %lu", 00437 (unsigned long) getpid()); 00438 00439 if (engine->config->zonefetch_filename) { 00440 zf_filename = strdup(engine->config->zonefetch_filename); 00441 } 00442 if (engine->config->zonelist_filename) { 00443 zl_filename = strdup(engine->config->zonelist_filename); 00444 } 00445 if (engine->config->group) { 00446 grp = strdup(engine->config->group); 00447 } 00448 if (engine->config->username) { 00449 usr = strdup(engine->config->username); 00450 } 00451 if (engine->config->chroot) { 00452 chrt = strdup(engine->config->chroot); 00453 } 00454 if (engine->config->log_filename) { 00455 log_filename = strdup(engine->config->log_filename); 00456 } 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 ods_log_verbose("zone fetcher done", result); 00464 if (zf_filename) { free((void*)zf_filename); } 00465 if (zl_filename) { free((void*)zl_filename); } 00466 if (grp) { free((void*)grp); } 00467 if (usr) { free((void*)usr); } 00468 if (chrt) { free((void*)chrt); } 00469 if (log_filename) { free((void*)log_filename); } 00470 00471 engine_cleanup(engine); 00472 engine = NULL; 00473 ods_log_close(); 00474 xmlCleanupParser(); 00475 xmlCleanupGlobals(); 00476 xmlCleanupThreads(); 00477 exit(result); 00478 00479 return 0; 00480 } 00481 00482 00487 static void 00488 reload_zonefetcher(engine_type* engine) 00489 { 00490 int result = 0; 00491 00492 ods_log_assert(engine); 00493 ods_log_assert(engine->config); 00494 00495 if (engine->config->zonefetch_filename) { 00496 if (engine->zfpid > 0) { 00497 result = kill(engine->zfpid, SIGHUP); 00498 if (result == -1) { 00499 ods_log_error("cannot reload zone fetcher: %s", 00500 strerror(errno)); 00501 } else { 00502 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid); 00503 } 00504 } else { 00505 ods_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 ods_log_assert(engine); 00522 ods_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 ods_log_error("cannot stop zone fetcher: %s", strerror(errno)); 00529 } else { 00530 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid); 00531 } 00532 engine->zfpid = -1; 00533 } else { 00534 ods_log_error("cannot stop zone fetcher: process id unknown"); 00535 } 00536 } 00537 return; 00538 } 00539 00540 00545 static ods_status 00546 engine_init_adapters(engine_type* engine) 00547 { 00548 size_t i = 0; 00549 ods_status status = ODS_STATUS_OK; 00550 00551 ods_log_assert(engine); 00552 ods_log_assert(engine->config); 00553 ods_log_debug("[%s] initialize adapters", engine_str); 00554 for (i=0; i < (size_t) engine->config->num_adapters; i++) { 00555 status = adapter_init(engine->config->adapters[i]); 00556 if (status != ODS_STATUS_OK) { 00557 return status; 00558 } 00559 } 00560 return status; 00561 } 00562 00563 00568 static ods_status 00569 engine_setup(engine_type* engine) 00570 { 00571 struct sigaction action; 00572 int result = 0; 00573 ods_status status = ODS_STATUS_OK; 00574 00575 ods_log_debug("[%s] signer setup", engine_str); 00576 if (!engine || !engine->config) { 00577 return ODS_STATUS_ASSERT_ERR; 00578 } 00579 00580 /* create command handler (before chowning socket file) */ 00581 engine->cmdhandler = cmdhandler_create(engine->allocator, 00582 engine->config->clisock_filename); 00583 if (!engine->cmdhandler) { 00584 ods_log_error("[%s] create command handler to %s failed", 00585 engine_str, engine->config->clisock_filename); 00586 return ODS_STATUS_CMDHANDLER_ERR; 00587 } 00588 00589 /* fork of fetcher */ 00590 if (start_zonefetcher(engine) != 0) { 00591 ods_log_error("[%s] cannot start zonefetcher", engine_str); 00592 return ODS_STATUS_ERR; 00593 } 00594 00595 /* initialize adapters */ 00596 status = engine_init_adapters(engine); 00597 if (status != ODS_STATUS_OK) { 00598 ods_log_error("[%s] initializing adapters failed", engine_str); 00599 return status; 00600 } 00601 00602 /* privdrop */ 00603 engine->uid = privuid(engine->config->username); 00604 engine->gid = privgid(engine->config->group); 00605 /* TODO: does piddir exists? */ 00606 /* remove the chown stuff: piddir? */ 00607 ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1); 00608 ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0); 00609 ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0); 00610 if (engine->config->log_filename && !engine->config->use_syslog) { 00611 ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0); 00612 } 00613 if (engine->config->working_dir && 00614 chdir(engine->config->working_dir) != 0) { 00615 ods_log_error("[%s] chdir to %s failed: %s", engine_str, 00616 engine->config->working_dir, strerror(errno)); 00617 return ODS_STATUS_CHDIR_ERR; 00618 } 00619 if (engine_privdrop(engine) != ODS_STATUS_OK) { 00620 ods_log_error("[%s] unable to drop privileges", engine_str); 00621 return ODS_STATUS_PRIVDROP_ERR; 00622 } 00623 00624 /* daemonize */ 00625 if (engine->daemonize) { 00626 switch ((engine->pid = fork())) { 00627 case -1: /* error */ 00628 ods_log_error("[%s] unable to fork daemon: %s", 00629 engine_str, strerror(errno)); 00630 return ODS_STATUS_FORK_ERR; 00631 case 0: /* child */ 00632 break; 00633 default: /* parent */ 00634 engine_cleanup(engine); 00635 engine = NULL; 00636 xmlCleanupParser(); 00637 xmlCleanupGlobals(); 00638 xmlCleanupThreads(); 00639 exit(0); 00640 } 00641 if (setsid() == -1) { 00642 ods_log_error("[%s] unable to setsid daemon (%s)", 00643 engine_str, strerror(errno)); 00644 return ODS_STATUS_SETSID_ERR; 00645 } 00646 } 00647 engine->pid = getpid(); 00648 ods_log_verbose("[%s] running as pid %lu", engine_str, 00649 (unsigned long) engine->pid); 00650 00651 /* catch signals */ 00652 signal_set_engine(engine); 00653 action.sa_handler = signal_handler; 00654 sigfillset(&action.sa_mask); 00655 action.sa_flags = 0; 00656 sigaction(SIGHUP, &action, NULL); 00657 sigaction(SIGTERM, &action, NULL); 00658 00659 /* set up hsm */ /* LEAK */ 00660 result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL); 00661 if (result != HSM_OK) { 00662 char *error = hsm_get_error(NULL); 00663 if (error != NULL) { 00664 ods_log_error("[%s] %s", engine_str, error); 00665 free(error); 00666 } 00667 ods_log_error("[%s] error initializing libhsm (errno %i)", 00668 engine_str, result); 00669 return ODS_STATUS_HSM_ERR; 00670 } 00671 00672 /* create workers */ 00673 engine_create_workers(engine); 00674 engine_create_drudgers(engine); 00675 00676 /* start command handler */ 00677 engine_start_cmdhandler(engine); 00678 00679 /* write pidfile */ 00680 if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) { 00681 hsm_close(); 00682 ods_log_error("[%s] unable to write pid file", engine_str); 00683 return ODS_STATUS_WRITE_PIDFILE_ERR; 00684 } 00685 00686 return ODS_STATUS_OK; 00687 } 00688 00689 00694 static int 00695 engine_all_zones_processed(engine_type* engine) 00696 { 00697 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00698 zone_type* zone = NULL; 00699 00700 ods_log_assert(engine); 00701 ods_log_assert(engine->zonelist); 00702 ods_log_assert(engine->zonelist->zones); 00703 00704 node = ldns_rbtree_first(engine->zonelist->zones); 00705 while (node && node != LDNS_RBTREE_NULL) { 00706 zone = (zone_type*) node->key; 00707 if (!zone->processed) { 00708 return 0; 00709 } 00710 node = ldns_rbtree_next(node); 00711 } 00712 return 1; 00713 } 00714 00715 00720 static void 00721 engine_run(engine_type* engine, int single_run) 00722 { 00723 if (!engine) { 00724 return; 00725 } 00726 ods_log_assert(engine); 00727 00728 engine_start_workers(engine); 00729 engine_start_drudgers(engine); 00730 00731 lock_basic_lock(&engine->signal_lock); 00732 /* [LOCK] signal */ 00733 engine->signal = SIGNAL_RUN; 00734 /* [UNLOCK] signal */ 00735 lock_basic_unlock(&engine->signal_lock); 00736 00737 while (!engine->need_to_exit && !engine->need_to_reload) { 00738 lock_basic_lock(&engine->signal_lock); 00739 /* [LOCK] signal */ 00740 engine->signal = signal_capture(engine->signal); 00741 switch (engine->signal) { 00742 case SIGNAL_RUN: 00743 ods_log_assert(1); 00744 break; 00745 case SIGNAL_RELOAD: 00746 engine->need_to_reload = 1; 00747 break; 00748 case SIGNAL_SHUTDOWN: 00749 engine->need_to_exit = 1; 00750 break; 00751 default: 00752 ods_log_warning("[%s] invalid signal captured: %d, " 00753 "keep running", engine_str, signal); 00754 engine->signal = SIGNAL_RUN; 00755 break; 00756 } 00757 /* [UNLOCK] signal */ 00758 lock_basic_unlock(&engine->signal_lock); 00759 00760 if (single_run) { 00761 engine->need_to_exit = engine_all_zones_processed(engine); 00762 } 00763 00764 lock_basic_lock(&engine->signal_lock); 00765 /* [LOCK] signal */ 00766 if (engine->signal == SIGNAL_RUN && !single_run) { 00767 ods_log_debug("[%s] taking a break", engine_str); 00768 lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600); 00769 } 00770 /* [UNLOCK] signal */ 00771 lock_basic_unlock(&engine->signal_lock); 00772 } 00773 ods_log_debug("[%s] signer halted", engine_str); 00774 engine_stop_drudgers(engine); 00775 engine_stop_workers(engine); 00776 return; 00777 } 00778 00779 00784 static void 00785 set_notify_ns(zone_type* zone, const char* cmd) 00786 { 00787 const char* str = NULL; 00788 const char* str2 = NULL; 00789 00790 ods_log_assert(cmd); 00791 ods_log_assert(zone); 00792 ods_log_assert(zone->name); 00793 ods_log_assert(zone->adoutbound); 00794 00795 if (zone->adoutbound->type == ADAPTER_FILE) { 00796 str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr); 00797 } else { 00798 str = cmd; 00799 } 00800 00801 str2 = ods_replace(str, "%zone", zone->name); 00802 free((void*)str); 00803 zone->notify_ns = (const char*) str2; 00804 ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns); 00805 return; 00806 } 00807 00808 00813 void 00814 engine_update_zones(engine_type* engine) 00815 { 00816 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00817 zone_type* zone = NULL; 00818 zone_type* delzone = NULL; 00819 task_type* task = NULL; 00820 ods_status status = ODS_STATUS_OK; 00821 int wake_up = 0; 00822 time_t now; 00823 00824 if (!engine || !engine->zonelist || !engine->zonelist->zones) { 00825 ods_log_error("[%s] cannot update zones: no engine or zonelist", 00826 engine_str); 00827 return; 00828 } 00829 ods_log_assert(engine); 00830 ods_log_assert(engine->zonelist); 00831 ods_log_assert(engine->zonelist->zones); 00832 00833 now = time_now(); 00834 reload_zonefetcher(engine); 00835 00836 lock_basic_lock(&engine->zonelist->zl_lock); 00837 /* [LOCK] zonelist */ 00838 node = ldns_rbtree_first(engine->zonelist->zones); 00839 while (node && node != LDNS_RBTREE_NULL) { 00840 zone = (zone_type*) node->data; 00841 task = NULL; /* reset task */ 00842 00843 if (zone->tobe_removed) { 00844 node = ldns_rbtree_next(node); 00845 00846 lock_basic_lock(&zone->zone_lock); 00847 /* [LOCK] zone */ 00848 delzone = zonelist_del_zone(engine->zonelist, zone); 00849 if (delzone) { 00850 lock_basic_lock(&engine->taskq->schedule_lock); 00851 /* [LOCK] schedule */ 00852 task = unschedule_task(engine->taskq, 00853 (task_type*) zone->task); 00854 /* [UNLOCK] schedule */ 00855 lock_basic_unlock(&engine->taskq->schedule_lock); 00856 } 00857 task_cleanup(task); 00858 task = NULL; 00859 /* [UNLOCK] zone */ 00860 lock_basic_unlock(&zone->zone_lock); 00861 00862 zone_cleanup(zone); 00863 zone = NULL; 00864 continue; 00865 } else if (zone->just_added) { 00866 00867 lock_basic_lock(&zone->zone_lock); 00868 ods_log_assert(!zone->task); 00869 zone->just_added = 0; 00870 /* notify nameserver */ 00871 if (engine->config->notify_command && !zone->notify_ns) { 00872 set_notify_ns(zone, engine->config->notify_command); 00873 } 00874 /* schedule task */ 00875 task = task_create(TASK_SIGNCONF, now, zone->name, zone); 00876 if (!task) { 00877 ods_log_crit("[%s] failed to create task for zone %s", 00878 engine_str, zone->name); 00879 } else { 00880 zone->task = task; 00881 lock_basic_lock(&engine->taskq->schedule_lock); 00882 /* [LOCK] schedule */ 00883 status = schedule_task(engine->taskq, task, 0); 00884 /* [UNLOCK] schedule */ 00885 lock_basic_unlock(&engine->taskq->schedule_lock); 00886 wake_up = 1; 00887 } 00888 /* zone fetcher enabled? */ 00889 zone->fetch = (engine->config->zonefetch_filename != NULL); 00890 lock_basic_unlock(&zone->zone_lock); 00891 } else if (zone->just_updated) { 00892 lock_basic_lock(&zone->zone_lock); 00893 ods_log_assert(zone->task); 00894 zone->just_updated = 0; 00895 /* reschedule task */ 00896 lock_basic_lock(&engine->taskq->schedule_lock); 00897 /* [LOCK] schedule */ 00898 task = unschedule_task(engine->taskq, (task_type*) zone->task); 00899 if (task != NULL) { 00900 ods_log_debug("[%s] reschedule task for zone %s", engine_str, 00901 zone->name); 00902 if (task->what != TASK_SIGNCONF) { 00903 task->halted = task->what; 00904 task->interrupt = TASK_SIGNCONF; 00905 } 00906 task->what = TASK_SIGNCONF; 00907 task->when = now; 00908 status = schedule_task(engine->taskq, task, 0); 00909 zone->task = task; 00910 } else { 00911 /* task not queued, being worked on? */ 00912 ods_log_debug("[%s] worker busy with zone %s, will update " 00913 "signconf as soon as possible", engine_str, zone->name); 00914 task = (task_type*) zone->task; 00915 task->interrupt = TASK_SIGNCONF; 00916 /* task->halted set by worker */ 00917 } 00918 /* [UNLOCK] schedule */ 00919 lock_basic_unlock(&engine->taskq->schedule_lock); 00920 lock_basic_unlock(&zone->zone_lock); 00921 00922 wake_up = 1; 00923 } 00924 00925 if (status != ODS_STATUS_OK) { 00926 ods_log_crit("[%s] failed to schedule task for zone %s: %s", 00927 engine_str, zone->name, ods_status2str(status)); 00928 task_cleanup(task); 00929 zone->task = NULL; 00930 } 00931 node = ldns_rbtree_next(node); 00932 } 00933 /* [UNLOCK] zonelist */ 00934 lock_basic_unlock(&engine->zonelist->zl_lock); 00935 if (wake_up) { 00936 engine_wakeup_workers(engine); 00937 } 00938 return; 00939 } 00940 00941 00946 static ods_status 00947 engine_recover(engine_type* engine) 00948 { 00949 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00950 zone_type* zone = NULL; 00951 ods_status status = ODS_STATUS_OK; 00952 ods_status result = ODS_STATUS_UNCHANGED; 00953 00954 if (!engine || !engine->zonelist || !engine->zonelist->zones) { 00955 ods_log_error("[%s] cannot update zones: no engine or zonelist", 00956 engine_str); 00957 return ODS_STATUS_OK; /* will trigger update zones */ 00958 } 00959 ods_log_assert(engine); 00960 ods_log_assert(engine->zonelist); 00961 ods_log_assert(engine->zonelist->zones); 00962 00963 lock_basic_lock(&engine->zonelist->zl_lock); 00964 /* [LOCK] zonelist */ 00965 node = ldns_rbtree_first(engine->zonelist->zones); 00966 while (node && node != LDNS_RBTREE_NULL) { 00967 zone = (zone_type*) node->data; 00968 00969 ods_log_assert(zone->just_added); 00970 status = zone_recover(zone); 00971 if (status == ODS_STATUS_OK) { 00972 ods_log_assert(zone->task); 00973 ods_log_assert(zone->zonedata); 00974 ods_log_assert(zone->signconf); 00975 /* notify nameserver */ 00976 if (engine->config->notify_command && !zone->notify_ns) { 00977 set_notify_ns(zone, engine->config->notify_command); 00978 } 00979 /* zone fetcher enabled? */ 00980 zone->fetch = (engine->config->zonefetch_filename != NULL); 00981 /* schedule task */ 00982 lock_basic_lock(&engine->taskq->schedule_lock); 00983 /* [LOCK] schedule */ 00984 status = schedule_task(engine->taskq, (task_type*) zone->task, 0); 00985 /* [UNLOCK] schedule */ 00986 lock_basic_unlock(&engine->taskq->schedule_lock); 00987 00988 if (status != ODS_STATUS_OK) { 00989 ods_log_crit("[%s] unable to schedule task for zone %s: %s", 00990 engine_str, zone->name, ods_status2str(status)); 00991 task_cleanup((task_type*) zone->task); 00992 zone->task = NULL; 00993 result = ODS_STATUS_OK; /* will trigger update zones */ 00994 } else { 00995 ods_log_verbose("[%s] recovered zone %s", engine_str, 00996 zone->name); 00997 /* recovery done */ 00998 zone->just_added = 0; 00999 } 01000 } else { 01001 if (status != ODS_STATUS_UNCHANGED) { 01002 ods_log_warning("[%s] unable to recover zone %s from backup," 01003 " performing full sign", engine_str, zone->name); 01004 } 01005 result = ODS_STATUS_OK; /* will trigger update zones */ 01006 } 01007 node = ldns_rbtree_next(node); 01008 } 01009 /* [UNLOCK] zonelist */ 01010 lock_basic_unlock(&engine->zonelist->zl_lock); 01011 return result; 01012 } 01013 01014 01019 void 01020 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize, 01021 int info, int single_run) 01022 { 01023 engine_type* engine = NULL; 01024 int use_syslog = 0; 01025 ods_status zl_changed = ODS_STATUS_UNCHANGED; 01026 ods_status status = ODS_STATUS_OK; 01027 int close_hsm = 0; 01028 01029 ods_log_assert(cfgfile); 01030 ods_log_init(NULL, use_syslog, cmdline_verbosity); 01031 ods_log_verbose("[%s] starting signer", engine_str); 01032 01033 /* initialize */ 01034 xmlInitGlobals(); 01035 xmlInitParser(); 01036 xmlInitThreads(); 01037 engine = engine_create(); 01038 if (!engine) { 01039 ods_fatal_exit("[%s] create failed", engine_str); 01040 return; 01041 } 01042 engine->daemonize = daemonize; 01043 01044 /* config */ 01045 engine->config = engine_config(engine->allocator, cfgfile, 01046 cmdline_verbosity); 01047 status = engine_config_check(engine->config); 01048 if (status != ODS_STATUS_OK) { 01049 ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile); 01050 goto earlyexit; 01051 } 01052 if (info) { 01053 engine_config_print(stdout, engine->config); /* for debugging */ 01054 goto earlyexit; 01055 } 01056 01057 /* open log */ 01058 ods_log_init(engine->config->log_filename, engine->config->use_syslog, 01059 engine->config->verbosity); 01060 01061 /* setup */ 01062 tzset(); /* for portability */ 01063 status = engine_setup(engine); 01064 if (status != ODS_STATUS_OK) { 01065 ods_log_error("[%s] setup failed: %s", engine_str, 01066 ods_status2str(status)); 01067 engine->need_to_exit = 1; 01068 if (status != ODS_STATUS_WRITE_PIDFILE_ERR) { 01069 /* command handler had not yet been started */ 01070 engine->cmdhandler_done = 1; 01071 } 01072 } else { 01073 /* setup ok, mark hsm open */ 01074 close_hsm = 1; 01075 } 01076 01077 /* run */ 01078 while (engine->need_to_exit == 0) { 01079 /* update zone list */ 01080 lock_basic_lock(&engine->zonelist->zl_lock); 01081 /* [LOCK] zonelist */ 01082 zl_changed = zonelist_update(engine->zonelist, 01083 engine->config->zonelist_filename); 01084 engine->zonelist->just_removed = 0; 01085 engine->zonelist->just_added = 0; 01086 engine->zonelist->just_updated = 0; 01087 /* [UNLOCK] zonelist */ 01088 lock_basic_unlock(&engine->zonelist->zl_lock); 01089 01090 if (engine->need_to_reload) { 01091 ods_log_info("[%s] signer reloading", engine_str); 01092 engine->need_to_reload = 0; 01093 } else { 01094 ods_log_info("[%s] signer started", engine_str); 01095 zl_changed = engine_recover(engine); 01096 } 01097 01098 /* update zones */ 01099 if (zl_changed == ODS_STATUS_OK) { 01100 ods_log_debug("[%s] commit zone list changes", engine_str); 01101 engine_update_zones(engine); 01102 ods_log_debug("[%s] signer configurations updated", engine_str); 01103 zl_changed = ODS_STATUS_UNCHANGED; 01104 } 01105 01106 engine_run(engine, single_run); 01107 } 01108 01109 /* shutdown */ 01110 ods_log_info("[%s] signer shutdown", engine_str); 01111 stop_zonefetcher(engine); 01112 if (close_hsm) { 01113 hsm_close(); 01114 } 01115 if (engine->cmdhandler != NULL) { 01116 engine_stop_cmdhandler(engine); 01117 } 01118 01119 earlyexit: 01120 if (engine && engine->config) { 01121 if (engine->config->pid_filename) { 01122 (void)unlink(engine->config->pid_filename); 01123 } 01124 if (engine->config->clisock_filename) { 01125 (void)unlink(engine->config->clisock_filename); 01126 } 01127 } 01128 engine_cleanup(engine); 01129 engine = NULL; 01130 ods_log_close(); 01131 xmlCleanupParser(); 01132 xmlCleanupGlobals(); 01133 xmlCleanupThreads(); 01134 return; 01135 } 01136 01137 01142 void 01143 engine_cleanup(engine_type* engine) 01144 { 01145 size_t i = 0; 01146 allocator_type* allocator; 01147 cond_basic_type signal_cond; 01148 lock_basic_type signal_lock; 01149 01150 if (!engine) { 01151 return; 01152 } 01153 allocator = engine->allocator; 01154 signal_cond = engine->signal_cond; 01155 signal_lock = engine->signal_lock; 01156 01157 if (engine->workers && engine->config) { 01158 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 01159 worker_cleanup(engine->workers[i]); 01160 } 01161 allocator_deallocate(allocator, (void*) engine->workers); 01162 } 01163 if (engine->drudgers && engine->config) { 01164 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 01165 worker_cleanup(engine->drudgers[i]); 01166 } 01167 allocator_deallocate(allocator, (void*) engine->drudgers); 01168 } 01169 zonelist_cleanup(engine->zonelist); 01170 schedule_cleanup(engine->taskq); 01171 fifoq_cleanup(engine->signq); 01172 cmdhandler_cleanup(engine->cmdhandler); 01173 engine_config_cleanup(engine->config); 01174 allocator_deallocate(allocator, (void*) engine); 01175 01176 lock_basic_destroy(&signal_lock); 01177 lock_basic_off(&signal_cond); 01178 allocator_cleanup(allocator); 01179 return; 01180 }