OpenDNSSEC-signer
1.3.8
|
00001 /* 00002 * $Id: engine.c 6238 2012-04-03 09:53:56Z 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/hsm.h" 00045 #include "shared/locks.h" 00046 #include "shared/log.h" 00047 #include "shared/privdrop.h" 00048 #include "shared/status.h" 00049 #include "shared/util.h" 00050 #include "signer/zone.h" 00051 #include "signer/zonelist.h" 00052 #include "tools/zone_fetcher.h" 00053 00054 #include <errno.h> 00055 #include <libhsm.h> 00056 #include <libxml/parser.h> 00057 #include <signal.h> 00058 #include <stdio.h> 00059 #include <stdlib.h> 00060 #include <string.h> 00061 #include <strings.h> 00062 #include <sys/socket.h> 00063 #include <sys/types.h> 00064 #include <sys/un.h> 00065 #include <time.h> 00066 #include <unistd.h> 00067 00068 static const char* engine_str = "engine"; 00069 00070 00075 static engine_type* 00076 engine_create(void) 00077 { 00078 engine_type* engine; 00079 allocator_type* allocator = allocator_create(malloc, free); 00080 if (!allocator) { 00081 return NULL; 00082 } 00083 engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type)); 00084 if (!engine) { 00085 allocator_cleanup(allocator); 00086 return NULL; 00087 } 00088 engine->allocator = allocator; 00089 engine->config = NULL; 00090 engine->workers = NULL; 00091 engine->drudgers = NULL; 00092 engine->cmdhandler = NULL; 00093 engine->cmdhandler_done = 0; 00094 engine->pid = -1; 00095 engine->zfpid = -1; 00096 engine->uid = -1; 00097 engine->gid = -1; 00098 engine->daemonize = 0; 00099 engine->need_to_exit = 0; 00100 engine->need_to_reload = 0; 00101 00102 lock_basic_init(&engine->signal_lock); 00103 lock_basic_set(&engine->signal_cond); 00104 lock_basic_lock(&engine->signal_lock); 00105 engine->signal = SIGNAL_INIT; 00106 lock_basic_unlock(&engine->signal_lock); 00107 00108 engine->zonelist = zonelist_create(engine->allocator); 00109 if (!engine->zonelist) { 00110 engine_cleanup(engine); 00111 return NULL; 00112 } 00113 engine->taskq = schedule_create(engine->allocator); 00114 if (!engine->taskq) { 00115 engine_cleanup(engine); 00116 return NULL; 00117 } 00118 engine->signq = fifoq_create(engine->allocator); 00119 if (!engine->signq) { 00120 engine_cleanup(engine); 00121 return NULL; 00122 } 00123 return engine; 00124 } 00125 00126 00131 static void* 00132 cmdhandler_thread_start(void* arg) 00133 { 00134 cmdhandler_type* cmd = (cmdhandler_type*) arg; 00135 ods_thread_blocksigs(); 00136 cmdhandler_start(cmd); 00137 return NULL; 00138 } 00139 static void 00140 engine_start_cmdhandler(engine_type* engine) 00141 { 00142 ods_log_assert(engine); 00143 ods_log_debug("[%s] start command handler", engine_str); 00144 engine->cmdhandler->engine = engine; 00145 ods_thread_create(&engine->cmdhandler->thread_id, 00146 cmdhandler_thread_start, engine->cmdhandler); 00147 return; 00148 } 00153 static int 00154 self_pipe_trick(engine_type* engine) 00155 { 00156 int sockfd, ret; 00157 struct sockaddr_un servaddr; 00158 const char* servsock_filename = ODS_SE_SOCKFILE; 00159 00160 ods_log_assert(engine); 00161 ods_log_assert(engine->cmdhandler); 00162 00163 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 00164 if (sockfd < 0) { 00165 ods_log_error("[%s] cannot connect to command handler: " 00166 "socket() failed: %s\n", engine_str, strerror(errno)); 00167 return 1; 00168 } else { 00169 bzero(&servaddr, sizeof(servaddr)); 00170 servaddr.sun_family = AF_UNIX; 00171 strncpy(servaddr.sun_path, servsock_filename, 00172 sizeof(servaddr.sun_path) - 1); 00173 00174 ret = connect(sockfd, (const struct sockaddr*) &servaddr, 00175 sizeof(servaddr)); 00176 if (ret != 0) { 00177 ods_log_error("[%s] cannot connect to command handler: " 00178 "connect() failed: %s\n", engine_str, strerror(errno)); 00179 close(sockfd); 00180 return 1; 00181 } else { 00182 /* self-pipe trick */ 00183 ods_writen(sockfd, "", 1); 00184 close(sockfd); 00185 } 00186 } 00187 return 0; 00188 } 00193 static void 00194 engine_stop_cmdhandler(engine_type* engine) 00195 { 00196 ods_log_assert(engine); 00197 if (!engine->cmdhandler) { 00198 return; 00199 } 00200 ods_log_debug("[%s] stop command handler", engine_str); 00201 engine->cmdhandler->need_to_exit = 1; 00202 if (self_pipe_trick(engine) == 0) { 00203 while (!engine->cmdhandler_done) { 00204 ods_log_debug("[%s] waiting for command handler to exit...", 00205 engine_str); 00206 sleep(1); 00207 } 00208 } else { 00209 ods_log_error("[%s] command handler self pipe trick failed, " 00210 "unclean shutdown", engine_str); 00211 } 00212 return; 00213 } 00214 00215 00220 static ods_status 00221 engine_privdrop(engine_type* engine) 00222 { 00223 ods_status status = ODS_STATUS_OK; 00224 uid_t uid = -1; 00225 gid_t gid = -1; 00226 00227 ods_log_assert(engine); 00228 ods_log_assert(engine->config); 00229 ods_log_debug("[%s] drop privileges", engine_str); 00230 00231 if (engine->config->username && engine->config->group) { 00232 ods_log_verbose("[%s] drop privileges to user %s, group %s", 00233 engine_str, engine->config->username, engine->config->group); 00234 } else if (engine->config->username) { 00235 ods_log_verbose("[%s] drop privileges to user %s", engine_str, 00236 engine->config->username); 00237 } else if (engine->config->group) { 00238 ods_log_verbose("[%s] drop privileges to group %s", engine_str, 00239 engine->config->group); 00240 } 00241 if (engine->config->chroot) { 00242 ods_log_verbose("[%s] chroot to %s", engine_str, 00243 engine->config->chroot); 00244 } 00245 status = privdrop(engine->config->username, engine->config->group, 00246 engine->config->chroot, &uid, &gid); 00247 engine->uid = uid; 00248 engine->gid = gid; 00249 privclose(engine->config->username, engine->config->group); 00250 return status; 00251 } 00252 00253 00258 static void 00259 engine_create_workers(engine_type* engine) 00260 { 00261 size_t i = 0; 00262 ods_log_assert(engine); 00263 ods_log_assert(engine->config); 00264 ods_log_assert(engine->allocator); 00265 engine->workers = (worker_type**) allocator_alloc(engine->allocator, 00266 ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*)); 00267 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00268 engine->workers[i] = worker_create(engine->allocator, i, 00269 WORKER_WORKER); 00270 } 00271 return; 00272 } 00273 static void 00274 engine_create_drudgers(engine_type* engine) 00275 { 00276 size_t i = 0; 00277 ods_log_assert(engine); 00278 ods_log_assert(engine->config); 00279 ods_log_assert(engine->allocator); 00280 engine->drudgers = (worker_type**) allocator_alloc(engine->allocator, 00281 ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*)); 00282 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00283 engine->drudgers[i] = worker_create(engine->allocator, i, 00284 WORKER_DRUDGER); 00285 } 00286 return; 00287 } 00288 static void* 00289 worker_thread_start(void* arg) 00290 { 00291 worker_type* worker = (worker_type*) arg; 00292 ods_thread_blocksigs(); 00293 worker_start(worker); 00294 return NULL; 00295 } 00296 static void 00297 engine_start_workers(engine_type* engine) 00298 { 00299 size_t i = 0; 00300 00301 ods_log_assert(engine); 00302 ods_log_assert(engine->config); 00303 ods_log_debug("[%s] start workers", engine_str); 00304 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00305 engine->workers[i]->need_to_exit = 0; 00306 engine->workers[i]->engine = (struct engine_struct*) engine; 00307 ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start, 00308 engine->workers[i]); 00309 } 00310 return; 00311 } 00312 void 00313 engine_start_drudgers(engine_type* engine) 00314 { 00315 size_t i = 0; 00316 00317 ods_log_assert(engine); 00318 ods_log_assert(engine->config); 00319 ods_log_debug("[%s] start drudgers", engine_str); 00320 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00321 engine->drudgers[i]->need_to_exit = 0; 00322 engine->drudgers[i]->engine = (struct engine_struct*) engine; 00323 ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start, 00324 engine->drudgers[i]); 00325 } 00326 return; 00327 } 00328 static void 00329 engine_stop_workers(engine_type* engine) 00330 { 00331 size_t i = 0; 00332 00333 ods_log_assert(engine); 00334 ods_log_assert(engine->config); 00335 ods_log_debug("[%s] stop workers", engine_str); 00336 /* tell them to exit and wake up sleepyheads */ 00337 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00338 engine->workers[i]->need_to_exit = 1; 00339 worker_wakeup(engine->workers[i]); 00340 } 00341 worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull); 00342 /* head count */ 00343 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00344 ods_log_debug("[%s] join worker %i", engine_str, i+1); 00345 ods_thread_join(engine->workers[i]->thread_id); 00346 engine->workers[i]->engine = NULL; 00347 } 00348 return; 00349 } 00350 void 00351 engine_stop_drudgers(engine_type* engine) 00352 { 00353 size_t i = 0; 00354 00355 ods_log_assert(engine); 00356 ods_log_assert(engine->config); 00357 ods_log_debug("[%s] stop drudgers", engine_str); 00358 /* tell them to exit and wake up sleepyheads */ 00359 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00360 engine->drudgers[i]->need_to_exit = 1; 00361 } 00362 worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold); 00363 00364 /* head count */ 00365 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 00366 ods_log_debug("[%s] join drudger %i", engine_str, i+1); 00367 ods_thread_join(engine->drudgers[i]->thread_id); 00368 engine->drudgers[i]->engine = NULL; 00369 } 00370 return; 00371 } 00372 00373 00378 void 00379 engine_wakeup_workers(engine_type* engine) 00380 { 00381 size_t i = 0; 00382 00383 ods_log_assert(engine); 00384 ods_log_assert(engine->config); 00385 ods_log_debug("[%s] wake up workers", engine_str); 00386 /* wake up sleepyheads */ 00387 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 00388 worker_wakeup(engine->workers[i]); 00389 } 00390 return; 00391 } 00392 00393 00398 static int 00399 start_zonefetcher(engine_type* engine) 00400 { 00401 pid_t zfpid = 0; 00402 int result = 0; 00403 char* zf_filename = NULL; 00404 char* zl_filename = NULL; 00405 char* log_filename = NULL; 00406 char* grp = NULL; 00407 char* usr = NULL; 00408 char* chrt = NULL; 00409 int use_syslog = 0; 00410 int verbosity = 0; 00411 00412 ods_log_assert(engine); 00413 ods_log_assert(engine->config); 00414 00415 if (!engine->config->zonefetch_filename) { 00416 /* zone fetcher disabled */ 00417 return 0; 00418 } 00419 00420 switch ((zfpid = fork())) { 00421 case -1: /* error */ 00422 ods_log_error("failed to fork zone fetcher: %s", 00423 strerror(errno)); 00424 return 1; 00425 case 0: /* child */ 00426 break; 00427 default: /* parent */ 00428 engine->zfpid = zfpid; 00429 return 0; 00430 } 00431 00432 if (setsid() == -1) { 00433 ods_log_error("failed to setsid zone fetcher: %s", 00434 strerror(errno)); 00435 return 1; 00436 } 00437 00438 ods_log_verbose("zone fetcher running as pid %lu", 00439 (unsigned long) getpid()); 00440 00441 if (engine->config->zonefetch_filename) { 00442 zf_filename = strdup(engine->config->zonefetch_filename); 00443 } 00444 if (engine->config->zonelist_filename) { 00445 zl_filename = strdup(engine->config->zonelist_filename); 00446 } 00447 if (engine->config->group) { 00448 grp = strdup(engine->config->group); 00449 } 00450 if (engine->config->username) { 00451 usr = strdup(engine->config->username); 00452 } 00453 if (engine->config->chroot) { 00454 chrt = strdup(engine->config->chroot); 00455 } 00456 if (engine->config->log_filename) { 00457 log_filename = strdup(engine->config->log_filename); 00458 } 00459 use_syslog = engine->config->use_syslog; 00460 verbosity = engine->config->verbosity; 00461 00462 result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr, 00463 chrt, log_filename, use_syslog, verbosity); 00464 00465 ods_log_verbose("zone fetcher done", result); 00466 if (zf_filename) { free((void*)zf_filename); } 00467 if (zl_filename) { free((void*)zl_filename); } 00468 if (grp) { free((void*)grp); } 00469 if (usr) { free((void*)usr); } 00470 if (chrt) { free((void*)chrt); } 00471 if (log_filename) { free((void*)log_filename); } 00472 00473 engine_cleanup(engine); 00474 engine = NULL; 00475 ods_log_close(); 00476 xmlCleanupParser(); 00477 xmlCleanupGlobals(); 00478 xmlCleanupThreads(); 00479 exit(result); 00480 00481 return 0; 00482 } 00483 00484 00489 static void 00490 reload_zonefetcher(engine_type* engine) 00491 { 00492 int result = 0; 00493 00494 ods_log_assert(engine); 00495 ods_log_assert(engine->config); 00496 00497 if (engine->config->zonefetch_filename) { 00498 if (engine->zfpid > 0) { 00499 result = kill(engine->zfpid, SIGHUP); 00500 if (result == -1) { 00501 ods_log_error("cannot reload zone fetcher: %s", 00502 strerror(errno)); 00503 } else { 00504 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid); 00505 } 00506 } else { 00507 ods_log_error("cannot reload zone fetcher: process id unknown"); 00508 } 00509 } 00510 return; 00511 } 00512 00513 00518 static void 00519 stop_zonefetcher(engine_type* engine) 00520 { 00521 int result = 0; 00522 00523 ods_log_assert(engine); 00524 ods_log_assert(engine->config); 00525 00526 if (engine->config->zonefetch_filename) { 00527 if (engine->zfpid > 0) { 00528 result = kill(engine->zfpid, SIGTERM); 00529 if (result == -1) { 00530 ods_log_error("cannot stop zone fetcher: %s", strerror(errno)); 00531 } else { 00532 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid); 00533 } 00534 engine->zfpid = -1; 00535 } else { 00536 ods_log_error("cannot stop zone fetcher: process id unknown"); 00537 } 00538 } 00539 return; 00540 } 00541 00542 00547 static ods_status 00548 engine_init_adapters(engine_type* engine) 00549 { 00550 size_t i = 0; 00551 ods_status status = ODS_STATUS_OK; 00552 00553 ods_log_assert(engine); 00554 ods_log_assert(engine->config); 00555 ods_log_debug("[%s] initialize adapters", engine_str); 00556 for (i=0; i < (size_t) engine->config->num_adapters; i++) { 00557 status = adapter_init(engine->config->adapters[i]); 00558 if (status != ODS_STATUS_OK) { 00559 return status; 00560 } 00561 } 00562 return status; 00563 } 00564 00565 00570 static ods_status 00571 engine_setup(engine_type* engine) 00572 { 00573 struct sigaction action; 00574 int result = 0; 00575 ods_status status = ODS_STATUS_OK; 00576 00577 ods_log_debug("[%s] signer setup", engine_str); 00578 if (!engine || !engine->config) { 00579 return ODS_STATUS_ASSERT_ERR; 00580 } 00581 00582 /* create command handler (before chowning socket file) */ 00583 engine->cmdhandler = cmdhandler_create(engine->allocator, 00584 engine->config->clisock_filename); 00585 if (!engine->cmdhandler) { 00586 ods_log_error("[%s] create command handler to %s failed", 00587 engine_str, engine->config->clisock_filename); 00588 return ODS_STATUS_CMDHANDLER_ERR; 00589 } 00590 00591 /* fork of fetcher */ 00592 if (start_zonefetcher(engine) != 0) { 00593 ods_log_error("[%s] cannot start zonefetcher", engine_str); 00594 return ODS_STATUS_ERR; 00595 } 00596 00597 /* initialize adapters */ 00598 status = engine_init_adapters(engine); 00599 if (status != ODS_STATUS_OK) { 00600 ods_log_error("[%s] initializing adapters failed", engine_str); 00601 return status; 00602 } 00603 00604 /* privdrop */ 00605 engine->uid = privuid(engine->config->username); 00606 engine->gid = privgid(engine->config->group); 00607 /* TODO: does piddir exists? */ 00608 /* remove the chown stuff: piddir? */ 00609 ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1); 00610 ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0); 00611 ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0); 00612 if (engine->config->log_filename && !engine->config->use_syslog) { 00613 ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0); 00614 } 00615 if (engine->config->working_dir && 00616 chdir(engine->config->working_dir) != 0) { 00617 ods_log_error("[%s] chdir to %s failed: %s", engine_str, 00618 engine->config->working_dir, strerror(errno)); 00619 return ODS_STATUS_CHDIR_ERR; 00620 } 00621 if (engine_privdrop(engine) != ODS_STATUS_OK) { 00622 ods_log_error("[%s] unable to drop privileges", engine_str); 00623 return ODS_STATUS_PRIVDROP_ERR; 00624 } 00625 00626 /* daemonize */ 00627 if (engine->daemonize) { 00628 switch ((engine->pid = fork())) { 00629 case -1: /* error */ 00630 ods_log_error("[%s] unable to fork daemon: %s", 00631 engine_str, strerror(errno)); 00632 return ODS_STATUS_FORK_ERR; 00633 case 0: /* child */ 00634 break; 00635 default: /* parent */ 00636 engine_cleanup(engine); 00637 engine = NULL; 00638 xmlCleanupParser(); 00639 xmlCleanupGlobals(); 00640 xmlCleanupThreads(); 00641 exit(0); 00642 } 00643 if (setsid() == -1) { 00644 ods_log_error("[%s] unable to setsid daemon (%s)", 00645 engine_str, strerror(errno)); 00646 return ODS_STATUS_SETSID_ERR; 00647 } 00648 } 00649 engine->pid = getpid(); 00650 ods_log_verbose("[%s] running as pid %lu", engine_str, 00651 (unsigned long) engine->pid); 00652 00653 /* catch signals */ 00654 signal_set_engine(engine); 00655 action.sa_handler = signal_handler; 00656 sigfillset(&action.sa_mask); 00657 action.sa_flags = 0; 00658 sigaction(SIGHUP, &action, NULL); 00659 sigaction(SIGTERM, &action, NULL); 00660 00661 /* set up hsm */ /* LEAK */ 00662 result = lhsm_open(engine->config->cfg_filename); 00663 if (result != HSM_OK) { 00664 return ODS_STATUS_HSM_ERR; 00665 } 00666 00667 /* create workers */ 00668 engine_create_workers(engine); 00669 engine_create_drudgers(engine); 00670 00671 /* start command handler */ 00672 engine_start_cmdhandler(engine); 00673 00674 /* write pidfile */ 00675 if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) { 00676 hsm_close(); 00677 ods_log_error("[%s] unable to write pid file", engine_str); 00678 return ODS_STATUS_WRITE_PIDFILE_ERR; 00679 } 00680 00681 return ODS_STATUS_OK; 00682 } 00683 00684 00689 static int 00690 engine_all_zones_processed(engine_type* engine) 00691 { 00692 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00693 zone_type* zone = NULL; 00694 00695 ods_log_assert(engine); 00696 ods_log_assert(engine->zonelist); 00697 ods_log_assert(engine->zonelist->zones); 00698 00699 node = ldns_rbtree_first(engine->zonelist->zones); 00700 while (node && node != LDNS_RBTREE_NULL) { 00701 zone = (zone_type*) node->key; 00702 if (!zone->processed) { 00703 return 0; 00704 } 00705 node = ldns_rbtree_next(node); 00706 } 00707 return 1; 00708 } 00709 00710 00715 static void 00716 engine_run(engine_type* engine, int single_run) 00717 { 00718 if (!engine) { 00719 return; 00720 } 00721 ods_log_assert(engine); 00722 00723 engine_start_workers(engine); 00724 engine_start_drudgers(engine); 00725 00726 lock_basic_lock(&engine->signal_lock); 00727 /* [LOCK] signal */ 00728 engine->signal = SIGNAL_RUN; 00729 /* [UNLOCK] signal */ 00730 lock_basic_unlock(&engine->signal_lock); 00731 00732 while (!engine->need_to_exit && !engine->need_to_reload) { 00733 lock_basic_lock(&engine->signal_lock); 00734 /* [LOCK] signal */ 00735 engine->signal = signal_capture(engine->signal); 00736 switch (engine->signal) { 00737 case SIGNAL_RUN: 00738 ods_log_assert(1); 00739 break; 00740 case SIGNAL_RELOAD: 00741 engine->need_to_reload = 1; 00742 break; 00743 case SIGNAL_SHUTDOWN: 00744 engine->need_to_exit = 1; 00745 break; 00746 default: 00747 ods_log_warning("[%s] invalid signal captured: %d, " 00748 "keep running", engine_str, signal); 00749 engine->signal = SIGNAL_RUN; 00750 break; 00751 } 00752 /* [UNLOCK] signal */ 00753 lock_basic_unlock(&engine->signal_lock); 00754 00755 if (single_run) { 00756 engine->need_to_exit = engine_all_zones_processed(engine); 00757 } 00758 00759 lock_basic_lock(&engine->signal_lock); 00760 /* [LOCK] signal */ 00761 if (engine->signal == SIGNAL_RUN && !single_run) { 00762 ods_log_debug("[%s] taking a break", engine_str); 00763 lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600); 00764 } 00765 /* [UNLOCK] signal */ 00766 lock_basic_unlock(&engine->signal_lock); 00767 } 00768 ods_log_debug("[%s] signer halted", engine_str); 00769 engine_stop_drudgers(engine); 00770 engine_stop_workers(engine); 00771 (void)lhsm_reopen(engine->config->cfg_filename); 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 zone->task = task; 00877 lock_basic_lock(&engine->taskq->schedule_lock); 00878 /* [LOCK] schedule */ 00879 status = schedule_task(engine->taskq, task, 0); 00880 /* [UNLOCK] schedule */ 00881 lock_basic_unlock(&engine->taskq->schedule_lock); 00882 wake_up = 1; 00883 } 00884 /* zone fetcher enabled? */ 00885 zone->fetch = (engine->config->zonefetch_filename != NULL); 00886 lock_basic_unlock(&zone->zone_lock); 00887 } else { /* always try to update signconf */ 00888 lock_basic_lock(&zone->zone_lock); 00889 ods_log_assert(zone->task); 00890 zone->just_updated = 0; 00891 /* reschedule task */ 00892 lock_basic_lock(&engine->taskq->schedule_lock); 00893 /* [LOCK] schedule */ 00894 task = unschedule_task(engine->taskq, (task_type*) zone->task); 00895 if (task != NULL) { 00896 ods_log_debug("[%s] reschedule task for zone %s", engine_str, 00897 zone->name); 00898 if (task->what != TASK_SIGNCONF) { 00899 task->halted = task->what; 00900 task->interrupt = TASK_SIGNCONF; 00901 } 00902 task->what = TASK_SIGNCONF; 00903 task->when = now; 00904 status = schedule_task(engine->taskq, task, 0); 00905 zone->task = task; 00906 } else { 00907 /* task not queued, being worked on? */ 00908 ods_log_debug("[%s] worker busy with zone %s, will update " 00909 "signconf as soon as possible", engine_str, zone->name); 00910 task = (task_type*) zone->task; 00911 task->interrupt = TASK_SIGNCONF; 00912 /* task->halted set by worker */ 00913 } 00914 /* [UNLOCK] schedule */ 00915 lock_basic_unlock(&engine->taskq->schedule_lock); 00916 lock_basic_unlock(&zone->zone_lock); 00917 00918 wake_up = 1; 00919 } 00920 00921 if (status != ODS_STATUS_OK) { 00922 ods_log_crit("[%s] failed to schedule task for zone %s: %s", 00923 engine_str, zone->name, ods_status2str(status)); 00924 task_cleanup(task); 00925 zone->task = NULL; 00926 } 00927 node = ldns_rbtree_next(node); 00928 } 00929 /* [UNLOCK] zonelist */ 00930 lock_basic_unlock(&engine->zonelist->zl_lock); 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 } 01068 } else { 01069 /* setup ok, mark hsm open */ 01070 close_hsm = 1; 01071 } 01072 01073 /* run */ 01074 while (engine->need_to_exit == 0) { 01075 /* update zone list */ 01076 lock_basic_lock(&engine->zonelist->zl_lock); 01077 /* [LOCK] zonelist */ 01078 zl_changed = zonelist_update(engine->zonelist, 01079 engine->config->zonelist_filename); 01080 engine->zonelist->just_removed = 0; 01081 engine->zonelist->just_added = 0; 01082 engine->zonelist->just_updated = 0; 01083 /* [UNLOCK] zonelist */ 01084 lock_basic_unlock(&engine->zonelist->zl_lock); 01085 01086 if (engine->need_to_reload) { 01087 ods_log_info("[%s] signer reloading", engine_str); 01088 engine->need_to_reload = 0; 01089 } else { 01090 ods_log_info("[%s] signer started", engine_str); 01091 zl_changed = engine_recover(engine); 01092 } 01093 01094 /* update zones */ 01095 if (zl_changed == ODS_STATUS_OK) { 01096 ods_log_debug("[%s] commit zone list changes", engine_str); 01097 engine_update_zones(engine); 01098 ods_log_debug("[%s] signer configurations updated", engine_str); 01099 zl_changed = ODS_STATUS_UNCHANGED; 01100 } 01101 01102 engine_run(engine, single_run); 01103 } 01104 01105 /* shutdown */ 01106 ods_log_info("[%s] signer shutdown", engine_str); 01107 stop_zonefetcher(engine); 01108 if (close_hsm) { 01109 hsm_close(); 01110 } 01111 if (engine->cmdhandler != NULL) { 01112 engine_stop_cmdhandler(engine); 01113 } 01114 01115 earlyexit: 01116 if (engine && engine->config) { 01117 if (engine->config->pid_filename) { 01118 (void)unlink(engine->config->pid_filename); 01119 } 01120 if (engine->config->clisock_filename) { 01121 (void)unlink(engine->config->clisock_filename); 01122 } 01123 } 01124 engine_cleanup(engine); 01125 engine = NULL; 01126 ods_log_close(); 01127 xmlCleanupParser(); 01128 xmlCleanupGlobals(); 01129 xmlCleanupThreads(); 01130 return; 01131 } 01132 01133 01138 void 01139 engine_cleanup(engine_type* engine) 01140 { 01141 size_t i = 0; 01142 allocator_type* allocator; 01143 cond_basic_type signal_cond; 01144 lock_basic_type signal_lock; 01145 01146 if (!engine) { 01147 return; 01148 } 01149 allocator = engine->allocator; 01150 signal_cond = engine->signal_cond; 01151 signal_lock = engine->signal_lock; 01152 01153 if (engine->workers && engine->config) { 01154 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) { 01155 worker_cleanup(engine->workers[i]); 01156 } 01157 allocator_deallocate(allocator, (void*) engine->workers); 01158 } 01159 if (engine->drudgers && engine->config) { 01160 for (i=0; i < (size_t) engine->config->num_signer_threads; i++) { 01161 worker_cleanup(engine->drudgers[i]); 01162 } 01163 allocator_deallocate(allocator, (void*) engine->drudgers); 01164 } 01165 zonelist_cleanup(engine->zonelist); 01166 schedule_cleanup(engine->taskq); 01167 fifoq_cleanup(engine->signq); 01168 cmdhandler_cleanup(engine->cmdhandler); 01169 engine_config_cleanup(engine->config); 01170 allocator_deallocate(allocator, (void*) engine); 01171 01172 lock_basic_destroy(&signal_lock); 01173 lock_basic_off(&signal_cond); 01174 allocator_cleanup(allocator); 01175 return; 01176 }