OpenDNSSEC-signer  1.3.15
engine.c
Go to the documentation of this file.
1 /*
2  * $Id: engine.c 7295 2013-09-11 10:18:25Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "daemon/cfg.h"
36 #include "daemon/cmdhandler.h"
37 #include "daemon/engine.h"
38 #include "daemon/signal.h"
39 #include "daemon/worker.h"
40 #include "scheduler/schedule.h"
41 #include "scheduler/task.h"
42 #include "shared/allocator.h"
43 #include "shared/file.h"
44 #include "shared/hsm.h"
45 #include "shared/locks.h"
46 #include "shared/log.h"
47 #include "shared/privdrop.h"
48 #include "shared/status.h"
49 #include "shared/util.h"
50 #include "signer/zone.h"
51 #include "signer/zonelist.h"
52 #include "tools/zone_fetcher.h"
53 
54 #include <errno.h>
55 #include <libhsm.h>
56 #include <libxml/parser.h>
57 #include <signal.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <strings.h>
62 #include <sys/socket.h>
63 #include <sys/types.h>
64 #include <sys/un.h>
65 #include <time.h>
66 #include <unistd.h>
67 
68 static const char* engine_str = "engine";
69 
70 
75 static engine_type*
76 engine_create(void)
77 {
78  engine_type* engine;
79  allocator_type* allocator = allocator_create(malloc, free);
80  if (!allocator) {
81  return NULL;
82  }
83  engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
84  if (!engine) {
85  allocator_cleanup(allocator);
86  return NULL;
87  }
88  engine->allocator = allocator;
89  engine->config = NULL;
90  engine->workers = NULL;
91  engine->drudgers = NULL;
92  engine->cmdhandler = NULL;
93  engine->cmdhandler_done = 0;
94  engine->pid = -1;
95  engine->zfpid = -1;
96  engine->uid = -1;
97  engine->gid = -1;
98  engine->daemonize = 0;
99  engine->need_to_exit = 0;
100  engine->need_to_reload = 0;
101 
102  lock_basic_init(&engine->signal_lock);
103  lock_basic_set(&engine->signal_cond);
104  lock_basic_lock(&engine->signal_lock);
106  engine->signal = SIGNAL_INIT;
107  engine->signal_locked = 0;
108  lock_basic_unlock(&engine->signal_lock);
109 
110  engine->zonelist = zonelist_create(engine->allocator);
111  if (!engine->zonelist) {
112  engine_cleanup(engine);
113  return NULL;
114  }
115  engine->taskq = schedule_create(engine->allocator);
116  if (!engine->taskq) {
117  engine_cleanup(engine);
118  return NULL;
119  }
120  engine->signq = fifoq_create(engine->allocator);
121  if (!engine->signq) {
122  engine_cleanup(engine);
123  return NULL;
124  }
125  return engine;
126 }
127 
128 
133 static void*
134 cmdhandler_thread_start(void* arg)
135 {
136  cmdhandler_type* cmd = (cmdhandler_type*) arg;
138  cmdhandler_start(cmd);
139  return NULL;
140 }
141 static void
142 engine_start_cmdhandler(engine_type* engine)
143 {
144  ods_log_assert(engine);
145  ods_log_debug("[%s] start command handler", engine_str);
146  engine->cmdhandler->engine = engine;
148  cmdhandler_thread_start, engine->cmdhandler);
149  return;
150 }
155 static int
156 self_pipe_trick(engine_type* engine)
157 {
158  int sockfd, ret;
159  struct sockaddr_un servaddr;
160  const char* servsock_filename = ODS_SE_SOCKFILE;
161 
162  ods_log_assert(engine);
163  ods_log_assert(engine->cmdhandler);
164 
165  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
166  if (sockfd < 0) {
167  ods_log_error("[%s] cannot connect to command handler: "
168  "socket() failed: %s\n", engine_str, strerror(errno));
169  return 1;
170  } else {
171  bzero(&servaddr, sizeof(servaddr));
172  servaddr.sun_family = AF_UNIX;
173  strncpy(servaddr.sun_path, servsock_filename,
174  sizeof(servaddr.sun_path) - 1);
175 
176  ret = connect(sockfd, (const struct sockaddr*) &servaddr,
177  sizeof(servaddr));
178  if (ret != 0) {
179  ods_log_error("[%s] cannot connect to command handler: "
180  "connect() failed: %s\n", engine_str, strerror(errno));
181  close(sockfd);
182  return 1;
183  } else {
184  /* self-pipe trick */
185  ods_writen(sockfd, "", 1);
186  close(sockfd);
187  }
188  }
189  return 0;
190 }
195 static void
196 engine_stop_cmdhandler(engine_type* engine)
197 {
198  ods_log_assert(engine);
199  if (!engine->cmdhandler) {
200  return;
201  }
202  ods_log_debug("[%s] stop command handler", engine_str);
203  engine->cmdhandler->need_to_exit = 1;
204  if (self_pipe_trick(engine) == 0) {
205  while (!engine->cmdhandler_done) {
206  ods_log_debug("[%s] waiting for command handler to exit...",
207  engine_str);
208  sleep(1);
209  }
210  } else {
211  ods_log_error("[%s] command handler self pipe trick failed, "
212  "unclean shutdown", engine_str);
213  }
214  return;
215 }
216 
217 
222 static ods_status
223 engine_privdrop(engine_type* engine)
224 {
225  ods_status status = ODS_STATUS_OK;
226  uid_t uid = -1;
227  gid_t gid = -1;
228 
229  ods_log_assert(engine);
230  ods_log_assert(engine->config);
231  ods_log_debug("[%s] drop privileges", engine_str);
232 
233  if (engine->config->username && engine->config->group) {
234  ods_log_verbose("[%s] drop privileges to user %s, group %s",
235  engine_str, engine->config->username, engine->config->group);
236  } else if (engine->config->username) {
237  ods_log_verbose("[%s] drop privileges to user %s", engine_str,
238  engine->config->username);
239  } else if (engine->config->group) {
240  ods_log_verbose("[%s] drop privileges to group %s", engine_str,
241  engine->config->group);
242  }
243  if (engine->config->chroot) {
244  ods_log_verbose("[%s] chroot to %s", engine_str,
245  engine->config->chroot);
246  }
247  status = privdrop(engine->config->username, engine->config->group,
248  engine->config->chroot, &uid, &gid);
249  engine->uid = uid;
250  engine->gid = gid;
251  privclose(engine->config->username, engine->config->group);
252  return status;
253 }
254 
255 
260 static void
261 engine_create_workers(engine_type* engine)
262 {
263  size_t i = 0;
264  ods_log_assert(engine);
265  ods_log_assert(engine->config);
266  ods_log_assert(engine->allocator);
267  engine->workers = (worker_type**) allocator_alloc(engine->allocator,
268  ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
269  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
270  engine->workers[i] = worker_create(engine->allocator, i,
271  WORKER_WORKER);
272  }
273  return;
274 }
275 static void
276 engine_create_drudgers(engine_type* engine)
277 {
278  size_t i = 0;
279  ods_log_assert(engine);
280  ods_log_assert(engine->config);
281  ods_log_assert(engine->allocator);
282  engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
283  ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
284  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
285  engine->drudgers[i] = worker_create(engine->allocator, i,
287  }
288  return;
289 }
290 static void*
291 worker_thread_start(void* arg)
292 {
293  worker_type* worker = (worker_type*) arg;
295  worker_start(worker);
296  return NULL;
297 }
298 static void
299 engine_start_workers(engine_type* engine)
300 {
301  size_t i = 0;
302 
303  ods_log_assert(engine);
304  ods_log_assert(engine->config);
305  ods_log_debug("[%s] start workers", engine_str);
306  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
307  engine->workers[i]->need_to_exit = 0;
308  engine->workers[i]->engine = (struct engine_struct*) engine;
309  ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
310  engine->workers[i]);
311  }
312  return;
313 }
314 void
316 {
317  size_t i = 0;
318 
319  ods_log_assert(engine);
320  ods_log_assert(engine->config);
321  ods_log_debug("[%s] start drudgers", engine_str);
322  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
323  engine->drudgers[i]->need_to_exit = 0;
324  engine->drudgers[i]->engine = (struct engine_struct*) engine;
325  ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
326  engine->drudgers[i]);
327  }
328  return;
329 }
330 static void
331 engine_stop_workers(engine_type* engine)
332 {
333  size_t i = 0;
334 
335  ods_log_assert(engine);
336  ods_log_assert(engine->config);
337  ods_log_debug("[%s] stop workers", engine_str);
338  /* tell them to exit and wake up sleepyheads */
339  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
340  engine->workers[i]->need_to_exit = 1;
341  worker_wakeup(engine->workers[i]);
342  }
343  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull);
344  /* head count */
345  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
346  ods_log_debug("[%s] join worker %i", engine_str, i+1);
347  ods_thread_join(engine->workers[i]->thread_id);
348  engine->workers[i]->engine = NULL;
349  }
350  return;
351 }
352 void
354 {
355  size_t i = 0;
356 
357  ods_log_assert(engine);
358  ods_log_assert(engine->config);
359  ods_log_debug("[%s] stop drudgers", engine_str);
360  /* tell them to exit and wake up sleepyheads */
361  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
362  engine->drudgers[i]->need_to_exit = 1;
363  }
364  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
365 
366  /* head count */
367  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
368  ods_log_debug("[%s] join drudger %i", engine_str, i+1);
369  ods_thread_join(engine->drudgers[i]->thread_id);
370  engine->drudgers[i]->engine = NULL;
371  }
372  return;
373 }
374 
375 
380 void
382 {
383  size_t i = 0;
384 
385  ods_log_assert(engine);
386  ods_log_assert(engine->config);
387  ods_log_debug("[%s] wake up workers", engine_str);
388  /* wake up sleepyheads */
389  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
390  worker_wakeup(engine->workers[i]);
391  }
392  return;
393 }
394 
395 
400 static int
401 start_zonefetcher(engine_type* engine)
402 {
403  pid_t zfpid = 0;
404  int result = 0;
405  char* zf_filename = NULL;
406  char* zl_filename = NULL;
407  char* log_filename = NULL;
408  char* grp = NULL;
409  char* usr = NULL;
410  char* chrt = NULL;
411  int use_syslog = 0;
412  int verbosity = 0;
413 
414  ods_log_assert(engine);
415  ods_log_assert(engine->config);
416 
417  if (!engine->config->zonefetch_filename) {
418  /* zone fetcher disabled */
419  return 0;
420  }
421 
422  switch ((zfpid = fork())) {
423  case -1: /* error */
424  ods_log_error("failed to fork zone fetcher: %s",
425  strerror(errno));
426  return 1;
427  case 0: /* child */
428  break;
429  default: /* parent */
430  engine->zfpid = zfpid;
431  return 0;
432  }
433 
434  if (setsid() == -1) {
435  ods_log_error("failed to setsid zone fetcher: %s",
436  strerror(errno));
437  return 1;
438  }
439 
440  ods_log_verbose("zone fetcher running as pid %lu",
441  (unsigned long) getpid());
442 
443  if (engine->config->zonefetch_filename) {
444  zf_filename = strdup(engine->config->zonefetch_filename);
445  }
446  if (engine->config->zonelist_filename) {
447  zl_filename = strdup(engine->config->zonelist_filename);
448  }
449  if (engine->config->group) {
450  grp = strdup(engine->config->group);
451  }
452  if (engine->config->username) {
453  usr = strdup(engine->config->username);
454  }
455  if (engine->config->chroot) {
456  chrt = strdup(engine->config->chroot);
457  }
458  if (engine->config->log_filename) {
459  log_filename = strdup(engine->config->log_filename);
460  }
461  use_syslog = engine->config->use_syslog;
462  verbosity = engine->config->verbosity;
463 
464  result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
465  chrt, log_filename, use_syslog, verbosity);
466 
467  ods_log_verbose("zone fetcher done", result);
468  if (zf_filename) { free((void*)zf_filename); }
469  if (zl_filename) { free((void*)zl_filename); }
470  if (grp) { free((void*)grp); }
471  if (usr) { free((void*)usr); }
472  if (chrt) { free((void*)chrt); }
473  if (log_filename) { free((void*)log_filename); }
474 
475  engine_cleanup(engine);
476  engine = NULL;
477  ods_log_close();
478  xmlCleanupParser();
479  xmlCleanupGlobals();
480  xmlCleanupThreads();
481  exit(result);
482 
483  return 0;
484 }
485 
486 
491 static void
492 reload_zonefetcher(engine_type* engine)
493 {
494  int result = 0;
495 
496  ods_log_assert(engine);
497  ods_log_assert(engine->config);
498 
499  if (engine->config->zonefetch_filename) {
500  if (engine->zfpid > 0) {
501  result = kill(engine->zfpid, SIGHUP);
502  if (result == -1) {
503  ods_log_error("cannot reload zone fetcher: %s",
504  strerror(errno));
505  } else {
506  ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
507  }
508  } else {
509  ods_log_error("cannot reload zone fetcher: process id unknown");
510  }
511  }
512  return;
513 }
514 
515 
520 static void
521 stop_zonefetcher(engine_type* engine)
522 {
523  int result = 0;
524 
525  ods_log_assert(engine);
526  ods_log_assert(engine->config);
527 
528  if (engine->config->zonefetch_filename) {
529  if (engine->zfpid > 0) {
530  result = kill(engine->zfpid, SIGTERM);
531  if (result == -1) {
532  ods_log_error("cannot stop zone fetcher: %s", strerror(errno));
533  } else {
534  ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
535  }
536  engine->zfpid = -1;
537  } else {
538  ods_log_error("cannot stop zone fetcher: process id unknown");
539  }
540  }
541  return;
542 }
543 
544 
549 static ods_status
550 engine_init_adapters(engine_type* engine)
551 {
552  size_t i = 0;
553  ods_status status = ODS_STATUS_OK;
554 
555  ods_log_assert(engine);
556  ods_log_assert(engine->config);
557  ods_log_debug("[%s] initialize adapters", engine_str);
558  for (i=0; i < (size_t) engine->config->num_adapters; i++) {
559  status = adapter_init(engine->config->adapters[i]);
560  if (status != ODS_STATUS_OK) {
561  return status;
562  }
563  }
564  return status;
565 }
566 
567 
572 static ods_status
573 engine_setup(engine_type* engine)
574 {
575  struct sigaction action;
576  int result = 0;
577  ods_status status = ODS_STATUS_OK;
578 
579  ods_log_debug("[%s] signer setup", engine_str);
580  if (!engine || !engine->config) {
581  return ODS_STATUS_ASSERT_ERR;
582  }
583 
584  /* create command handler (before chowning socket file) */
585  engine->cmdhandler = cmdhandler_create(engine->allocator,
586  engine->config->clisock_filename);
587  if (!engine->cmdhandler) {
588  ods_log_error("[%s] create command handler to %s failed",
589  engine_str, engine->config->clisock_filename);
591  }
592 
593  /* fork of fetcher */
594  if (start_zonefetcher(engine) != 0) {
595  ods_log_error("[%s] cannot start zonefetcher", engine_str);
596  return ODS_STATUS_ERR;
597  }
598 
599  /* initialize adapters */
600  status = engine_init_adapters(engine);
601  if (status != ODS_STATUS_OK) {
602  ods_log_error("[%s] initializing adapters failed", engine_str);
603  return status;
604  }
605 
606  /* privdrop */
607  engine->uid = privuid(engine->config->username);
608  engine->gid = privgid(engine->config->group);
609  /* TODO: does piddir exists? */
610  /* remove the chown stuff: piddir? */
611  ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
612  ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
613  ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
614  if (engine->config->log_filename && !engine->config->use_syslog) {
615  ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
616  }
617  if (engine->config->working_dir &&
618  chdir(engine->config->working_dir) != 0) {
619  ods_log_error("[%s] chdir to %s failed: %s", engine_str,
620  engine->config->working_dir, strerror(errno));
621  return ODS_STATUS_CHDIR_ERR;
622  }
623  if (engine_privdrop(engine) != ODS_STATUS_OK) {
624  ods_log_error("[%s] unable to drop privileges", engine_str);
626  }
627 
628  /* daemonize */
629  if (engine->daemonize) {
630  switch ((engine->pid = fork())) {
631  case -1: /* error */
632  ods_log_error("[%s] unable to fork daemon: %s",
633  engine_str, strerror(errno));
634  return ODS_STATUS_FORK_ERR;
635  case 0: /* child */
636  break;
637  default: /* parent */
638  engine_cleanup(engine);
639  engine = NULL;
640  xmlCleanupParser();
641  xmlCleanupGlobals();
642  xmlCleanupThreads();
643  exit(0);
644  }
645  if (setsid() == -1) {
646  ods_log_error("[%s] unable to setsid daemon (%s)",
647  engine_str, strerror(errno));
648  return ODS_STATUS_SETSID_ERR;
649  }
650  }
651  engine->pid = getpid();
652  ods_log_verbose("[%s] running as pid %lu", engine_str,
653  (unsigned long) engine->pid);
654 
655  /* catch signals */
656  signal_set_engine(engine);
657  action.sa_handler = signal_handler;
658  sigfillset(&action.sa_mask);
659  action.sa_flags = 0;
660  sigaction(SIGHUP, &action, NULL);
661  sigaction(SIGTERM, &action, NULL);
662 
663  /* set up hsm */ /* LEAK */
664  result = lhsm_open(engine->config->cfg_filename);
665  if (result != HSM_OK) {
666  return ODS_STATUS_HSM_ERR;
667  }
668 
669  /* create workers */
670  engine_create_workers(engine);
671  engine_create_drudgers(engine);
672 
673  /* start command handler */
674  engine_start_cmdhandler(engine);
675 
676  /* write pidfile */
677  if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
678  hsm_close();
679  ods_log_error("[%s] unable to write pid file", engine_str);
681  }
682 
683  return ODS_STATUS_OK;
684 }
685 
686 
691 static int
692 engine_all_zones_processed(engine_type* engine)
693 {
694  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
695  zone_type* zone = NULL;
696 
697  ods_log_assert(engine);
698  ods_log_assert(engine->zonelist);
699  ods_log_assert(engine->zonelist->zones);
700 
701  node = ldns_rbtree_first(engine->zonelist->zones);
702  while (node && node != LDNS_RBTREE_NULL) {
703  zone = (zone_type*) node->key;
704  if (!zone->processed) {
705  return 0;
706  }
707  node = ldns_rbtree_next(node);
708  }
709  return 1;
710 }
711 
712 
717 static void
718 engine_run(engine_type* engine, int single_run)
719 {
720  if (!engine) {
721  return;
722  }
723  ods_log_assert(engine);
724 
725  engine_start_workers(engine);
726  engine_start_drudgers(engine);
727 
728  lock_basic_lock(&engine->signal_lock);
730  engine->signal = SIGNAL_RUN;
731  engine->signal_locked = 0;
732  lock_basic_unlock(&engine->signal_lock);
733 
734  while (!engine->need_to_exit && !engine->need_to_reload) {
735  lock_basic_lock(&engine->signal_lock);
737  engine->signal = signal_capture(engine->signal);
738  switch (engine->signal) {
739  case SIGNAL_RUN:
740  ods_log_assert(1);
741  break;
742  case SIGNAL_RELOAD:
743  engine->need_to_reload = 1;
744  break;
745  case SIGNAL_SHUTDOWN:
746  engine->need_to_exit = 1;
747  break;
748  default:
749  ods_log_warning("[%s] invalid signal captured: %d, "
750  "keep running", engine_str, signal);
751  engine->signal = SIGNAL_RUN;
752  break;
753  }
754  engine->signal_locked = 0;
755  lock_basic_unlock(&engine->signal_lock);
756 
757  if (single_run) {
758  engine->need_to_exit = engine_all_zones_processed(engine);
759  }
760 
761  lock_basic_lock(&engine->signal_lock);
763  if (engine->signal == SIGNAL_RUN && !single_run) {
764  ods_log_debug("[%s] taking a break", engine_str);
765  lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
766  }
767  engine->signal_locked = 0;
768  lock_basic_unlock(&engine->signal_lock);
769  }
770  ods_log_debug("[%s] signer halted", engine_str);
771  engine_stop_drudgers(engine);
772  engine_stop_workers(engine);
773  (void)lhsm_reopen(engine->config->cfg_filename);
774  return;
775 }
776 
777 
782 static void
783 set_notify_ns(zone_type* zone, const char* cmd)
784 {
785  const char* str = NULL;
786  const char* str2 = NULL;
787 
788  ods_log_assert(cmd);
789  ods_log_assert(zone);
790  ods_log_assert(zone->name);
791  ods_log_assert(zone->adoutbound);
792 
793  if (zone->adoutbound->type == ADAPTER_FILE) {
794  str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
795  } else {
796  str = cmd;
797  }
798 
799  str2 = ods_replace(str, "%zone", zone->name);
800  free((void*)str);
801  zone->notify_ns = (const char*) str2;
802  ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
803  return;
804 }
805 
806 
811 void
813 {
814  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
815  zone_type* zone = NULL;
816  zone_type* delzone = NULL;
817  task_type* task = NULL;
818  ods_status status = ODS_STATUS_OK;
819  int wake_up = 0;
820  time_t now;
821 
822  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
823  ods_log_error("[%s] cannot update zones: no engine or zonelist",
824  engine_str);
825  return;
826  }
827  ods_log_assert(engine);
828  ods_log_assert(engine->zonelist);
829  ods_log_assert(engine->zonelist->zones);
830 
831  now = time_now();
832  reload_zonefetcher(engine);
833 
834  lock_basic_lock(&engine->zonelist->zl_lock);
836  node = ldns_rbtree_first(engine->zonelist->zones);
837  while (node && node != LDNS_RBTREE_NULL) {
838  zone = (zone_type*) node->data;
839  task = NULL; /* reset task */
840 
841  if (zone->tobe_removed) {
842  node = ldns_rbtree_next(node);
843 
844  lock_basic_lock(&zone->zone_lock);
846  delzone = zonelist_del_zone(engine->zonelist, zone);
847  if (delzone) {
850  task = unschedule_task(engine->taskq,
851  (task_type*) zone->task);
852  engine->taskq->schedule_locked = 0;
854  }
855  task_cleanup(task);
856  task = NULL;
857  zone->zone_locked = 0;
859 
860  zone_cleanup(zone);
861  zone = NULL;
862  continue;
863  } else if (zone->just_added) {
864 
865  lock_basic_lock(&zone->zone_lock);
867  ods_log_assert(!zone->task);
868  zone->just_added = 0;
869  /* notify nameserver */
870  if (engine->config->notify_command && !zone->notify_ns) {
871  set_notify_ns(zone, engine->config->notify_command);
872  }
873  /* schedule task */
874  task = task_create(TASK_SIGNCONF, now, zone->name, zone);
875  if (!task) {
876  ods_log_crit("[%s] failed to create task for zone %s",
877  engine_str, zone->name);
878  } else {
879  zone->task = task;
882  status = schedule_task(engine->taskq, task, 0);
883  engine->taskq->schedule_locked = 0;
885  wake_up = 1;
886  }
887  /* zone fetcher enabled? */
888  zone->fetch = (engine->config->zonefetch_filename != NULL);
889  zone->zone_locked = 0;
891  } else { /* always try to update signconf */
892  lock_basic_lock(&zone->zone_lock);
894  ods_log_assert(zone->task);
895  zone->just_updated = 0;
896  /* reschedule task */
899  task = unschedule_task(engine->taskq, (task_type*) zone->task);
900  if (task != NULL) {
901  ods_log_debug("[%s] reschedule task for zone %s", engine_str,
902  zone->name);
903  if (task->what != TASK_SIGNCONF) {
904  task->halted = task->what;
905  task->interrupt = TASK_SIGNCONF;
906  }
907  task->what = TASK_SIGNCONF;
908  task->when = now;
909  status = schedule_task(engine->taskq, task, 0);
910  zone->task = task;
911  } else {
912  /* task not queued, being worked on? */
913  ods_log_debug("[%s] worker busy with zone %s, will update "
914  "signconf as soon as possible", engine_str, zone->name);
915  task = (task_type*) zone->task;
916  task->interrupt = TASK_SIGNCONF;
917  /* task->halted set by worker */
918  }
919  engine->taskq->schedule_locked = 0;
921  zone->zone_locked = 0;
923 
924  wake_up = 1;
925  }
926 
927  if (status != ODS_STATUS_OK) {
928  ods_log_crit("[%s] failed to schedule task for zone %s: %s",
929  engine_str, zone->name, ods_status2str(status));
930  task_cleanup(task);
931  zone->task = NULL;
932  }
933  node = ldns_rbtree_next(node);
934  }
935  engine->zonelist->zl_locked = 0;
937  if (wake_up) {
938  engine_wakeup_workers(engine);
939  }
940  return;
941 }
942 
943 
948 static ods_status
949 engine_recover(engine_type* engine)
950 {
951  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
952  zone_type* zone = NULL;
953  ods_status status = ODS_STATUS_OK;
955 
956  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
957  ods_log_error("[%s] cannot update zones: no engine or zonelist",
958  engine_str);
959  return ODS_STATUS_OK; /* will trigger update zones */
960  }
961  ods_log_assert(engine);
962  ods_log_assert(engine->zonelist);
963  ods_log_assert(engine->zonelist->zones);
964 
965  lock_basic_lock(&engine->zonelist->zl_lock);
967  node = ldns_rbtree_first(engine->zonelist->zones);
968  while (node && node != LDNS_RBTREE_NULL) {
969  zone = (zone_type*) node->data;
970 
971  ods_log_assert(zone->just_added);
972  status = zone_recover(zone);
973  if (status == ODS_STATUS_OK) {
974  ods_log_assert(zone->task);
975  ods_log_assert(zone->zonedata);
976  ods_log_assert(zone->signconf);
977  /* notify nameserver */
978  if (engine->config->notify_command && !zone->notify_ns) {
979  set_notify_ns(zone, engine->config->notify_command);
980  }
981  /* zone fetcher enabled? */
982  zone->fetch = (engine->config->zonefetch_filename != NULL);
983  /* schedule task */
986  status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
987  engine->taskq->schedule_locked = 0;
989 
990  if (status != ODS_STATUS_OK) {
991  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
992  engine_str, zone->name, ods_status2str(status));
993  task_cleanup((task_type*) zone->task);
994  zone->task = NULL;
995  result = ODS_STATUS_OK; /* will trigger update zones */
996  } else {
997  ods_log_verbose("[%s] recovered zone %s", engine_str,
998  zone->name);
999  /* recovery done */
1000  zone->just_added = 0;
1001  }
1002  } else {
1003  if (status != ODS_STATUS_UNCHANGED) {
1004  ods_log_warning("[%s] unable to recover zone %s from backup,"
1005  " performing full sign", engine_str, zone->name);
1006  }
1007  result = ODS_STATUS_OK; /* will trigger update zones */
1008  }
1009  node = ldns_rbtree_next(node);
1010  }
1011  engine->zonelist->zl_locked = 0;
1012  lock_basic_unlock(&engine->zonelist->zl_lock);
1013  return result;
1014 }
1015 
1016 
1021 void
1022 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
1023  int info, int single_run)
1024 {
1025  engine_type* engine = NULL;
1026  int use_syslog = 0;
1027  ods_status zl_changed = ODS_STATUS_UNCHANGED;
1028  ods_status status = ODS_STATUS_OK;
1029  int close_hsm = 0;
1030 
1031  ods_log_assert(cfgfile);
1032  ods_log_init(NULL, use_syslog, cmdline_verbosity);
1033  ods_log_verbose("[%s] starting signer", engine_str);
1034 
1035  /* initialize */
1036  xmlInitGlobals();
1037  xmlInitParser();
1038  xmlInitThreads();
1039  engine = engine_create();
1040  if (!engine) {
1041  ods_fatal_exit("[%s] create failed", engine_str);
1042  return;
1043  }
1044  engine->daemonize = daemonize;
1045 
1046  /* config */
1047  engine->config = engine_config(engine->allocator, cfgfile,
1048  cmdline_verbosity);
1049  status = engine_config_check(engine->config);
1050  if (status != ODS_STATUS_OK) {
1051  ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
1052  goto earlyexit;
1053  }
1054  if (info) {
1055  engine_config_print(stdout, engine->config); /* for debugging */
1056  goto earlyexit;
1057  }
1058  /* check pidfile */
1059  if (!util_check_pidfile(engine->config->pid_filename)) {
1060  exit(1);
1061  }
1062  /* open log */
1063  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
1064  engine->config->verbosity);
1065  /* setup */
1066  tzset(); /* for portability */
1067  status = engine_setup(engine);
1068  if (status != ODS_STATUS_OK) {
1069  ods_log_error("[%s] setup failed: %s", engine_str,
1070  ods_status2str(status));
1071  engine->need_to_exit = 1;
1072  if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
1073  /* command handler had not yet been started */
1074  engine->cmdhandler_done = 1;
1075  }
1076  } else {
1077  /* setup ok, mark hsm open */
1078  close_hsm = 1;
1079  }
1080 
1081  /* run */
1082  while (engine->need_to_exit == 0) {
1083  /* update zone list */
1084  lock_basic_lock(&engine->zonelist->zl_lock);
1085  engine->zonelist->zl_locked = 1;
1086  zl_changed = zonelist_update(engine->zonelist,
1087  engine->config->zonelist_filename);
1088  engine->zonelist->just_removed = 0;
1089  engine->zonelist->just_added = 0;
1090  engine->zonelist->just_updated = 0;
1091  engine->zonelist->zl_locked = 0;
1092  lock_basic_unlock(&engine->zonelist->zl_lock);
1093 
1094  if (engine->need_to_reload) {
1095  ods_log_info("[%s] signer reloading", engine_str);
1096  engine->need_to_reload = 0;
1097  } else {
1098  ods_log_info("[%s] signer started", engine_str);
1099  zl_changed = engine_recover(engine);
1100  }
1101 
1102  /* update zones */
1103  if (zl_changed == ODS_STATUS_OK) {
1104  ods_log_debug("[%s] commit zone list changes", engine_str);
1105  engine_update_zones(engine);
1106  ods_log_debug("[%s] signer configurations updated", engine_str);
1107  zl_changed = ODS_STATUS_UNCHANGED;
1108  }
1109 
1110  engine_run(engine, single_run);
1111  }
1112 
1113  /* shutdown */
1114  ods_log_info("[%s] signer shutdown", engine_str);
1115  stop_zonefetcher(engine);
1116  if (close_hsm) {
1117  hsm_close();
1118  }
1119  if (engine->cmdhandler != NULL) {
1120  engine_stop_cmdhandler(engine);
1121  }
1122 
1123 earlyexit:
1124  if (engine && engine->config) {
1125  if (engine->config->pid_filename) {
1126  (void)unlink(engine->config->pid_filename);
1127  }
1128  if (engine->config->clisock_filename) {
1129  (void)unlink(engine->config->clisock_filename);
1130  }
1131  }
1132  engine_cleanup(engine);
1133  engine = NULL;
1134  ods_log_close();
1135  xmlCleanupParser();
1136  xmlCleanupGlobals();
1137  xmlCleanupThreads();
1138  return;
1139 }
1140 
1141 
1146 void
1148 {
1149  size_t i = 0;
1150  allocator_type* allocator;
1151  cond_basic_type signal_cond;
1152  lock_basic_type signal_lock;
1153 
1154  if (!engine) {
1155  return;
1156  }
1157  allocator = engine->allocator;
1158  signal_cond = engine->signal_cond;
1159  signal_lock = engine->signal_lock;
1160 
1161  if (engine->workers && engine->config) {
1162  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
1163  worker_cleanup(engine->workers[i]);
1164  }
1165  allocator_deallocate(allocator, (void*) engine->workers);
1166  }
1167  if (engine->drudgers && engine->config) {
1168  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
1169  worker_cleanup(engine->drudgers[i]);
1170  }
1171  allocator_deallocate(allocator, (void*) engine->drudgers);
1172  }
1173  zonelist_cleanup(engine->zonelist);
1174  schedule_cleanup(engine->taskq);
1175  fifoq_cleanup(engine->signq);
1176  cmdhandler_cleanup(engine->cmdhandler);
1177  engine_config_cleanup(engine->config);
1178  allocator_deallocate(allocator, (void*) engine);
1179 
1180  lock_basic_destroy(&signal_lock);
1181  lock_basic_off(&signal_cond);
1182  allocator_cleanup(allocator);
1183  return;
1184 }