OpenDNSSEC-signer  1.4.1
engine.c
Go to the documentation of this file.
1 /*
2  * $Id: engine.c 7096 2013-04-17 08:04:35Z 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/engine.h"
37 #include "daemon/signal.h"
38 #include "shared/allocator.h"
39 #include "shared/duration.h"
40 #include "shared/file.h"
41 #include "shared/hsm.h"
42 #include "shared/locks.h"
43 #include "shared/log.h"
44 #include "shared/privdrop.h"
45 #include "shared/status.h"
46 #include "shared/util.h"
47 #include "signer/zonelist.h"
48 #include "wire/tsig.h"
49 
50 #include <errno.h>
51 #include <libhsm.h>
52 #include <libxml/parser.h>
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <strings.h>
58 #include <sys/socket.h>
59 #include <sys/types.h>
60 #include <sys/un.h>
61 #include <time.h>
62 #include <unistd.h>
63 
64 static const char* engine_str = "engine";
65 
66 
71 static engine_type*
72 engine_create(void)
73 {
74  engine_type* engine;
75  allocator_type* allocator = allocator_create(malloc, free);
76  if (!allocator) {
77  ods_log_error("[%s] unable to create engine: allocator_create() "
78  "failed", engine_str);
79  return NULL;
80  }
81  engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
82  if (!engine) {
83  ods_log_error("[%s] unable to create engine: allocator_alloc() "
84  "failed", engine_str);
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->dnshandler = NULL;
95  engine->xfrhandler = NULL;
96  engine->pid = -1;
97  engine->uid = -1;
98  engine->gid = -1;
99  engine->daemonize = 0;
100  engine->need_to_exit = 0;
101  engine->need_to_reload = 0;
102  lock_basic_init(&engine->signal_lock);
103  lock_basic_set(&engine->signal_cond);
104  lock_basic_lock(&engine->signal_lock);
105  engine->signal = SIGNAL_INIT;
106  lock_basic_unlock(&engine->signal_lock);
107  engine->zonelist = zonelist_create(engine->allocator);
108  if (!engine->zonelist) {
109  engine_cleanup(engine);
110  return NULL;
111  }
112  engine->taskq = schedule_create(engine->allocator);
113  if (!engine->taskq) {
114  engine_cleanup(engine);
115  return NULL;
116  }
117  engine->signq = fifoq_create(engine->allocator);
118  if (!engine->signq) {
119  engine_cleanup(engine);
120  return NULL;
121  }
122  return engine;
123 }
124 
125 
130 static void*
131 cmdhandler_thread_start(void* arg)
132 {
133  cmdhandler_type* cmd = (cmdhandler_type*) arg;
135  cmdhandler_start(cmd);
136  return NULL;
137 }
138 static void
139 engine_start_cmdhandler(engine_type* engine)
140 {
141  ods_log_assert(engine);
142  ods_log_debug("[%s] start command handler", engine_str);
143  engine->cmdhandler->engine = engine;
145  cmdhandler_thread_start, engine->cmdhandler);
146  return;
147 }
152 static int
153 self_pipe_trick(engine_type* engine)
154 {
155  int sockfd, ret;
156  struct sockaddr_un servaddr;
157  const char* servsock_filename = ODS_SE_SOCKFILE;
158  ods_log_assert(engine);
159  ods_log_assert(engine->cmdhandler);
160  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
161  if (sockfd < 0) {
162  ods_log_error("[%s] unable to connect to command handler: "
163  "socket() failed (%s)", engine_str, strerror(errno));
164  return 1;
165  } else {
166  bzero(&servaddr, sizeof(servaddr));
167  servaddr.sun_family = AF_UNIX;
168  strncpy(servaddr.sun_path, servsock_filename,
169  sizeof(servaddr.sun_path) - 1);
170  ret = connect(sockfd, (const struct sockaddr*) &servaddr,
171  sizeof(servaddr));
172  if (ret != 0) {
173  ods_log_error("[%s] unable to connect to command handler: "
174  "connect() failed (%s)", engine_str, strerror(errno));
175  close(sockfd);
176  return 1;
177  } else {
178  /* self-pipe trick */
179  ods_writen(sockfd, "", 1);
180  close(sockfd);
181  }
182  }
183  return 0;
184 }
189 static void
190 engine_stop_cmdhandler(engine_type* engine)
191 {
192  ods_log_assert(engine);
193  if (!engine->cmdhandler) {
194  return;
195  }
196  ods_log_debug("[%s] stop command handler", engine_str);
197  engine->cmdhandler->need_to_exit = 1;
198  if (self_pipe_trick(engine) == 0) {
199  while (!engine->cmdhandler_done) {
200  ods_log_debug("[%s] waiting for command handler to exit...",
201  engine_str);
202  sleep(1);
203  }
204  } else {
205  ods_log_error("[%s] command handler self pipe trick failed, "
206  "unclean shutdown", engine_str);
207  }
208  return;
209 }
210 
211 
216 static void*
217 dnshandler_thread_start(void* arg)
218 {
219  dnshandler_type* dnshandler = (dnshandler_type*) arg;
220  dnshandler_start(dnshandler);
221  return NULL;
222 }
223 static void
224 engine_start_dnshandler(engine_type* engine)
225 {
226  if (!engine || !engine->dnshandler) {
227  return;
228  }
229  ods_log_debug("[%s] start dnshandler", engine_str);
230  engine->dnshandler->engine = engine;
232  dnshandler_thread_start, engine->dnshandler);
233  return;
234 }
235 static void
236 engine_stop_dnshandler(engine_type* engine)
237 {
238  if (!engine || !engine->dnshandler || !engine->dnshandler->thread_id) {
239  return;
240  }
241  ods_log_debug("[%s] stop dnshandler", engine_str);
242  engine->dnshandler->need_to_exit = 1;
243  dnshandler_signal(engine->dnshandler);
244  ods_log_debug("[%s] join dnshandler", engine_str);
246  engine->dnshandler->engine = NULL;
247  return;
248 }
249 
250 
255 static void*
256 xfrhandler_thread_start(void* arg)
257 {
258  xfrhandler_type* xfrhandler = (xfrhandler_type*) arg;
259  xfrhandler_start(xfrhandler);
260  return NULL;
261 }
262 static void
263 engine_start_xfrhandler(engine_type* engine)
264 {
265  if (!engine || !engine->xfrhandler) {
266  return;
267  }
268  ods_log_debug("[%s] start xfrhandler", engine_str);
269  engine->xfrhandler->engine = engine;
271  xfrhandler_thread_start, engine->xfrhandler);
272  /* This might be the wrong place to mark the xfrhandler started but
273  * if its isn't done here we might try to shutdown and stop it before
274  * it has marked itself started
275  */
276  engine->xfrhandler->started = 1;
277  return;
278 }
279 static void
280 engine_stop_xfrhandler(engine_type* engine)
281 {
282  if (!engine || !engine->xfrhandler) {
283  return;
284  }
285  ods_log_debug("[%s] stop xfrhandler", engine_str);
286  engine->xfrhandler->need_to_exit = 1;
287  xfrhandler_signal(engine->xfrhandler);
288  ods_log_debug("[%s] join xfrhandler", engine_str);
289  if (engine->xfrhandler->started) {
291  engine->xfrhandler->started = 0;
292  }
293  engine->xfrhandler->engine = NULL;
294  return;
295 }
296 
297 
302 static ods_status
303 engine_privdrop(engine_type* engine)
304 {
305  ods_status status = ODS_STATUS_OK;
306  uid_t uid = -1;
307  gid_t gid = -1;
308  ods_log_assert(engine);
309  ods_log_assert(engine->config);
310  ods_log_debug("[%s] drop privileges", engine_str);
311  if (engine->config->username && engine->config->group) {
312  ods_log_verbose("[%s] drop privileges to user %s, group %s",
313  engine_str, engine->config->username, engine->config->group);
314  } else if (engine->config->username) {
315  ods_log_verbose("[%s] drop privileges to user %s", engine_str,
316  engine->config->username);
317  } else if (engine->config->group) {
318  ods_log_verbose("[%s] drop privileges to group %s", engine_str,
319  engine->config->group);
320  }
321  if (engine->config->chroot) {
322  ods_log_verbose("[%s] chroot to %s", engine_str,
323  engine->config->chroot);
324  }
325  status = privdrop(engine->config->username, engine->config->group,
326  engine->config->chroot, &uid, &gid);
327  engine->uid = uid;
328  engine->gid = gid;
329  privclose(engine->config->username, engine->config->group);
330  return status;
331 }
332 
333 
338 static void
339 engine_create_workers(engine_type* engine)
340 {
341  size_t i = 0;
342  ods_log_assert(engine);
343  ods_log_assert(engine->config);
344  ods_log_assert(engine->allocator);
345  engine->workers = (worker_type**) allocator_alloc(engine->allocator,
346  ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
347  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
348  engine->workers[i] = worker_create(engine->allocator, i,
349  WORKER_WORKER);
350  }
351  return;
352 }
353 static void
354 engine_create_drudgers(engine_type* engine)
355 {
356  size_t i = 0;
357  ods_log_assert(engine);
358  ods_log_assert(engine->config);
359  ods_log_assert(engine->allocator);
360  engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
361  ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
362  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
363  engine->drudgers[i] = worker_create(engine->allocator, i,
365  }
366  return;
367 }
368 static void*
369 worker_thread_start(void* arg)
370 {
371  worker_type* worker = (worker_type*) arg;
373  worker_start(worker);
374  return NULL;
375 }
376 static void
377 engine_start_workers(engine_type* engine)
378 {
379  size_t i = 0;
380  ods_log_assert(engine);
381  ods_log_assert(engine->config);
382  ods_log_debug("[%s] start workers", engine_str);
383  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
384  engine->workers[i]->need_to_exit = 0;
385  engine->workers[i]->engine = (void*) engine;
386  ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
387  engine->workers[i]);
388  }
389  return;
390 }
391 void
393 {
394  size_t i = 0;
395  ods_log_assert(engine);
396  ods_log_assert(engine->config);
397  ods_log_debug("[%s] start drudgers", engine_str);
398  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
399  engine->drudgers[i]->need_to_exit = 0;
400  engine->drudgers[i]->engine = (void*) engine;
401  ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
402  engine->drudgers[i]);
403  }
404  return;
405 }
406 static void
407 engine_stop_workers(engine_type* engine)
408 {
409  size_t i = 0;
410  ods_log_assert(engine);
411  ods_log_assert(engine->config);
412  ods_log_debug("[%s] stop workers", engine_str);
413  /* tell them to exit and wake up sleepyheads */
414  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
415  engine->workers[i]->need_to_exit = 1;
416  worker_wakeup(engine->workers[i]);
417  }
418  ods_log_debug("[%s] notify workers", engine_str);
419  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull);
420  /* head count */
421  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
422  ods_log_debug("[%s] join worker %i", engine_str, i+1);
423  ods_thread_join(engine->workers[i]->thread_id);
424  engine->workers[i]->engine = NULL;
425  }
426  return;
427 }
428 void
430 {
431  size_t i = 0;
432  ods_log_assert(engine);
433  ods_log_assert(engine->config);
434  ods_log_debug("[%s] stop drudgers", engine_str);
435  /* tell them to exit and wake up sleepyheads */
436  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
437  engine->drudgers[i]->need_to_exit = 1;
438  }
439  ods_log_debug("[%s] notify drudgers", engine_str);
440  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
441  /* head count */
442  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
443  ods_log_debug("[%s] join drudger %i", engine_str, i+1);
444  ods_thread_join(engine->drudgers[i]->thread_id);
445  engine->drudgers[i]->engine = NULL;
446  }
447  return;
448 }
449 
450 
455 void
457 {
458  size_t i = 0;
459  ods_log_assert(engine);
460  ods_log_assert(engine->config);
461  ods_log_debug("[%s] wake up workers", engine_str);
462  /* wake up sleepyheads */
463  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
464  worker_wakeup(engine->workers[i]);
465  }
466  return;
467 }
468 
469 
474 static ods_status
475 engine_setup(engine_type* engine)
476 {
477  ods_status status = ODS_STATUS_OK;
478  struct sigaction action;
479  int result = 0;
480  int sockets[2] = {0,0};
481 
482  ods_log_debug("[%s] setup signer engine", engine_str);
483  if (!engine || !engine->config) {
484  return ODS_STATUS_ASSERT_ERR;
485  }
486  /* set edns */
488 
489  /* create command handler (before chowning socket file) */
490  engine->cmdhandler = cmdhandler_create(engine->allocator,
491  engine->config->clisock_filename);
492  if (!engine->cmdhandler) {
494  }
495  engine->dnshandler = dnshandler_create(engine->allocator,
496  engine->config->interfaces);
497  engine->xfrhandler = xfrhandler_create(engine->allocator);
498  if (!engine->xfrhandler) {
500  }
501  if (engine->dnshandler) {
502  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == -1) {
504  }
505  engine->xfrhandler->dnshandler.fd = sockets[0];
506  engine->dnshandler->xfrhandler.fd = sockets[1];
507  status = dnshandler_listen(engine->dnshandler);
508  if (status != ODS_STATUS_OK) {
509  ods_log_error("[%s] setup: unable to listen to sockets (%s)",
510  engine_str, ods_status2str(status));
511  }
512  }
513  /* privdrop */
514  engine->uid = privuid(engine->config->username);
515  engine->gid = privgid(engine->config->group);
516  /* TODO: does piddir exists? */
517  /* remove the chown stuff: piddir? */
518  ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
519  ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
520  ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
521  if (engine->config->log_filename && !engine->config->use_syslog) {
522  ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
523  }
524  if (engine->config->working_dir &&
525  chdir(engine->config->working_dir) != 0) {
526  ods_log_error("[%s] setup: unable to chdir to %s (%s)", engine_str,
527  engine->config->working_dir, strerror(errno));
528  return ODS_STATUS_CHDIR_ERR;
529  }
530  if (engine_privdrop(engine) != ODS_STATUS_OK) {
532  }
533  /* daemonize */
534  if (engine->daemonize) {
535  switch ((engine->pid = fork())) {
536  case -1: /* error */
537  ods_log_error("[%s] setup: unable to fork daemon (%s)",
538  engine_str, strerror(errno));
539  return ODS_STATUS_FORK_ERR;
540  case 0: /* child */
541  break;
542  default: /* parent */
543  engine_cleanup(engine);
544  engine = NULL;
545  xmlCleanupParser();
546  xmlCleanupGlobals();
547  xmlCleanupThreads();
548  exit(0);
549  }
550  if (setsid() == -1) {
551  ods_log_error("[%s] setup: unable to setsid daemon (%s)",
552  engine_str, strerror(errno));
553  return ODS_STATUS_SETSID_ERR;
554  }
555  }
556  engine->pid = getpid();
557  ods_log_verbose("[%s] running as pid %lu", engine_str,
558  (unsigned long) engine->pid);
559  /* catch signals */
560  signal_set_engine(engine);
561  action.sa_handler = signal_handler;
562  sigfillset(&action.sa_mask);
563  action.sa_flags = 0;
564  sigaction(SIGTERM, &action, NULL);
565  sigaction(SIGHUP, &action, NULL);
566  sigaction(SIGINT, &action, NULL);
567  sigaction(SIGILL, &action, NULL);
568  sigaction(SIGUSR1, &action, NULL);
569  sigaction(SIGALRM, &action, NULL);
570  sigaction(SIGCHLD, &action, NULL);
571  action.sa_handler = SIG_IGN;
572  sigaction(SIGPIPE, &action, NULL);
573  /* set up hsm */ /* LEAK */
574  result = lhsm_open(engine->config->cfg_filename);
575  if (result != HSM_OK) {
576  return ODS_STATUS_HSM_ERR;
577  }
578  /* create workers/drudgers */
579  engine_create_workers(engine);
580  engine_create_drudgers(engine);
581  /* start cmd/dns/xfr handlers */
582  engine_start_cmdhandler(engine);
583  engine_start_dnshandler(engine);
584  engine_start_xfrhandler(engine);
585  tsig_handler_init(engine->allocator);
586  /* write pidfile */
587  if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
588  hsm_close();
590  }
591  /* setup done */
592  return ODS_STATUS_OK;
593 }
594 
595 
600 static int
601 engine_all_zones_processed(engine_type* engine)
602 {
603  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
604  zone_type* zone = NULL;
605 
606  ods_log_assert(engine);
607  ods_log_assert(engine->zonelist);
608  ods_log_assert(engine->zonelist->zones);
609 
610  node = ldns_rbtree_first(engine->zonelist->zones);
611  while (node && node != LDNS_RBTREE_NULL) {
612  zone = (zone_type*) node->key;
613  ods_log_assert(zone);
614  ods_log_assert(zone->db);
615  if (!zone->db->is_processed) {
616  return 0;
617  }
618  node = ldns_rbtree_next(node);
619  }
620  return 1;
621 }
622 
623 
628 static void
629 engine_run(engine_type* engine, int single_run)
630 {
631  if (!engine) {
632  return;
633  }
634  engine_start_workers(engine);
635  engine_start_drudgers(engine);
636 
637  lock_basic_lock(&engine->signal_lock);
638  engine->signal = SIGNAL_RUN;
639  lock_basic_unlock(&engine->signal_lock);
640 
641  while (!engine->need_to_exit && !engine->need_to_reload) {
642  lock_basic_lock(&engine->signal_lock);
643  engine->signal = signal_capture(engine->signal);
644  switch (engine->signal) {
645  case SIGNAL_RUN:
646  ods_log_assert(1);
647  break;
648  case SIGNAL_RELOAD:
649  engine->need_to_reload = 1;
650  break;
651  case SIGNAL_SHUTDOWN:
652  engine->need_to_exit = 1;
653  break;
654  default:
655  ods_log_warning("[%s] invalid signal %d captured, "
656  "keep running", engine_str, signal);
657  engine->signal = SIGNAL_RUN;
658  break;
659  }
660  lock_basic_unlock(&engine->signal_lock);
661 
662  if (single_run) {
663  engine->need_to_exit = engine_all_zones_processed(engine);
664  }
665  lock_basic_lock(&engine->signal_lock);
666  if (engine->signal == SIGNAL_RUN && !single_run) {
667  ods_log_debug("[%s] taking a break", engine_str);
668  lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
669  }
670  lock_basic_unlock(&engine->signal_lock);
671  }
672  ods_log_debug("[%s] signer halted", engine_str);
673  engine_stop_drudgers(engine);
674  engine_stop_workers(engine);
675  (void)lhsm_reopen(engine->config->cfg_filename);
676  return;
677 }
678 
679 
684 static void
685 set_notify_ns(zone_type* zone, const char* cmd)
686 {
687  const char* str = NULL;
688  const char* str2 = NULL;
689  char* token = NULL;
690  ods_log_assert(cmd);
691  ods_log_assert(zone);
692  ods_log_assert(zone->name);
693  ods_log_assert(zone->adoutbound);
694  if (zone->adoutbound->type == ADAPTER_FILE) {
695  str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
696  } else {
697  str = cmd;
698  }
699  str2 = ods_replace(str, "%zone", zone->name);
700  if (str2) {
701  free((void*)str);
702 
703  ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
704  ods_str_trim((char*) str2);
705  str = str2;
706  if (*str) {
707  token = NULL;
708  while ((token = strtok((char*) str, " "))) {
709  if (*token) {
710  ods_str_list_add(&zone->notify_args, token);
711  }
712  str = NULL;
713  }
714  }
715  zone->notify_command = (char*) str2;
716  zone->notify_ns = zone->notify_args[0];
717  } else {
718  ods_log_error("[%s] unable to set notify ns: replace zone failed",
719  engine_str);
720  }
721  return;
722 }
723 
724 
729 static int
730 dnsconfig_zone(engine_type* engine, zone_type* zone)
731 {
732  int numdns = 0;
733  ods_log_assert(engine);
734  ods_log_assert(engine->xfrhandler);
735  ods_log_assert(engine->xfrhandler->netio);
736  ods_log_assert(zone);
737  ods_log_assert(zone->adinbound);
738  ods_log_assert(zone->adoutbound);
739  ods_log_assert(zone->name);
740 
741  if (zone->adinbound->type == ADAPTER_DNS) {
742  /* zone transfer handler */
743  if (!zone->xfrd) {
744  ods_log_debug("[%s] add transfer handler for zone %s",
745  engine_str, zone->name);
746  zone->xfrd = xfrd_create((void*) engine->xfrhandler,
747  (void*) zone);
748  ods_log_assert(zone->xfrd);
750  &zone->xfrd->handler);
751  } else if (!zone->xfrd->serial_disk_acquired) {
752  xfrd_set_timer_now(zone->xfrd);
753  }
754  numdns++;
755  } else if (zone->xfrd) {
757  &zone->xfrd->handler);
758  xfrd_cleanup(zone->xfrd);
759  zone->xfrd = NULL;
760  }
761  if (zone->adoutbound->type == ADAPTER_DNS) {
762  /* notify handler */
763  if (!zone->notify) {
764  ods_log_debug("[%s] add notify handler for zone %s",
765  engine_str, zone->name);
766  zone->notify = notify_create((void*) engine->xfrhandler,
767  (void*) zone);
768  ods_log_assert(zone->notify);
770  &zone->notify->handler);
771  }
772  numdns++;
773  } else if (zone->notify) {
775  &zone->notify->handler);
776  notify_cleanup(zone->notify);
777  zone->notify = NULL;
778  }
779  return numdns;
780 }
781 
782 
787 void
789 {
790  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
791  zone_type* zone = NULL;
792  zone_type* delzone = NULL;
793  task_type* task = NULL;
794  ods_status status = ODS_STATUS_OK;
795  unsigned wake_up = 0;
796  int warnings = 0;
797  time_t now = 0;
798 
799  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
800  return;
801  }
802  now = time_now();
803 
804  ods_log_debug("[%s] commit zone list changes", engine_str);
805  lock_basic_lock(&engine->zonelist->zl_lock);
806  node = ldns_rbtree_first(engine->zonelist->zones);
807  while (node && node != LDNS_RBTREE_NULL) {
808  zone = (zone_type*) node->data;
809  task = NULL; /* reset task */
810 
811  if (zone->zl_status == ZONE_ZL_REMOVED) {
812  node = ldns_rbtree_next(node);
813  lock_basic_lock(&zone->zone_lock);
814  delzone = zonelist_del_zone(engine->zonelist, zone);
815  if (delzone) {
817  task = unschedule_task(engine->taskq,
818  (task_type*) zone->task);
820  }
821  task_cleanup(task);
822  task = NULL;
825  &zone->xfrd->handler);
826  zone_cleanup(zone);
827  zone = NULL;
828  continue;
829  } else if (zone->zl_status == ZONE_ZL_ADDED) {
830  lock_basic_lock(&zone->zone_lock);
831  ods_log_assert(!zone->task);
832  /* set notify nameserver command */
833  if (engine->config->notify_command && !zone->notify_ns) {
834  set_notify_ns(zone, engine->config->notify_command);
835  }
836  /* create task */
837  task = task_create(TASK_SIGNCONF, now, zone);
839  if (!task) {
840  ods_log_crit("[%s] unable to create task for zone %s: "
841  "task_create() failed", engine_str, zone->name);
842  node = ldns_rbtree_next(node);
843  continue;
844  }
845  }
846  /* load adapter config */
847  status = adapter_load_config(zone->adinbound);
848  if (status != ODS_STATUS_OK) {
849  ods_log_error("[%s] unable to load config for inbound adapter "
850  "for zone %s: %s", engine_str, zone->name,
851  ods_status2str(status));
852  }
853  status = adapter_load_config(zone->adoutbound);
854  if (status != ODS_STATUS_OK) {
855  ods_log_error("[%s] unable to load config for outbound adapter "
856  "for zone %s: %s", engine_str, zone->name,
857  ods_status2str(status));
858  }
859  /* for dns adapters */
860  warnings += dnsconfig_zone(engine, zone);
861 
862  if (zone->zl_status == ZONE_ZL_ADDED) {
863  ods_log_assert(task);
864  lock_basic_lock(&zone->zone_lock);
865  zone->task = task;
868  status = schedule_task(engine->taskq, task, 0);
870  } else if (zl_changed == ODS_STATUS_OK) {
871  /* always try to update signconf */
872  lock_basic_lock(&zone->zone_lock);
873  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
875  }
876  if (status != ODS_STATUS_OK) {
877  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
878  engine_str, zone->name, ods_status2str(status));
879  } else {
880  wake_up = 1;
881  zone->zl_status = ZONE_ZL_OK;
882  }
883  node = ldns_rbtree_next(node);
884  }
886  if (engine->dnshandler) {
888  (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
889  } else if (warnings) {
890  ods_log_warning("[%s] no dnshandler/listener configured, but zones "
891  "are configured with dns adapters: notify and zone transfer "
892  "requests will not work properly", engine_str);
893  }
894  if (wake_up) {
895  engine_wakeup_workers(engine);
896  }
897  return;
898 }
899 
900 
905 static ods_status
906 engine_recover(engine_type* engine)
907 {
908  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
909  zone_type* zone = NULL;
910  ods_status status = ODS_STATUS_OK;
912 
913  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
914  ods_log_error("[%s] cannot recover zones: no engine or zonelist",
915  engine_str);
916  return ODS_STATUS_ERR; /* no need to update zones */
917  }
918  ods_log_assert(engine);
919  ods_log_assert(engine->zonelist);
920  ods_log_assert(engine->zonelist->zones);
921 
922  lock_basic_lock(&engine->zonelist->zl_lock);
923  /* [LOCK] zonelist */
924  node = ldns_rbtree_first(engine->zonelist->zones);
925  while (node && node != LDNS_RBTREE_NULL) {
926  zone = (zone_type*) node->data;
927 
929  status = zone_recover2(zone);
930  if (status == ODS_STATUS_OK) {
931  ods_log_assert(zone->task);
932  ods_log_assert(zone->db);
933  ods_log_assert(zone->signconf);
934  /* notify nameserver */
935  if (engine->config->notify_command && !zone->notify_ns) {
936  set_notify_ns(zone, engine->config->notify_command);
937  }
938  /* schedule task */
940  /* [LOCK] schedule */
941  status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
942  /* [UNLOCK] schedule */
944 
945  if (status != ODS_STATUS_OK) {
946  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
947  engine_str, zone->name, ods_status2str(status));
948  task_cleanup((task_type*) zone->task);
949  zone->task = NULL;
950  result = ODS_STATUS_OK; /* will trigger update zones */
951  } else {
952  ods_log_debug("[%s] recovered zone %s", engine_str,
953  zone->name);
954  /* recovery done */
955  zone->zl_status = ZONE_ZL_OK;
956  }
957  } else {
958  if (status != ODS_STATUS_UNCHANGED) {
959  ods_log_warning("[%s] unable to recover zone %s from backup,"
960  " performing full sign", engine_str, zone->name);
961  }
962  result = ODS_STATUS_OK; /* will trigger update zones */
963  }
964  node = ldns_rbtree_next(node);
965  }
966  /* [UNLOCK] zonelist */
968  return result;
969 }
970 
971 
976 void
977 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
978  int info, int single_run)
979 {
980  engine_type* engine = NULL;
981  int use_syslog = 0;
982  ods_status zl_changed = ODS_STATUS_UNCHANGED;
983  ods_status status = ODS_STATUS_OK;
984  int close_hsm = 0;
985 
986  ods_log_assert(cfgfile);
987  ods_log_init(NULL, use_syslog, cmdline_verbosity);
988  ods_log_verbose("[%s] starting signer", engine_str);
989 
990  /* initialize */
991  xmlInitGlobals();
992  xmlInitParser();
993  xmlInitThreads();
994  engine = engine_create();
995  if (!engine) {
996  ods_fatal_exit("[%s] create failed", engine_str);
997  return;
998  }
999  engine->daemonize = daemonize;
1000 
1001  /* config */
1002  engine->config = engine_config(engine->allocator, cfgfile,
1003  cmdline_verbosity);
1004  status = engine_config_check(engine->config);
1005  if (status != ODS_STATUS_OK) {
1006  ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
1007  goto earlyexit;
1008  }
1009  if (info) {
1010  engine_config_print(stdout, engine->config); /* for debugging */
1011  goto earlyexit;
1012  }
1013  /* check pidfile */
1014  if (!util_check_pidfile(engine->config->pid_filename)) {
1015  exit(1);
1016  }
1017  /* open log */
1018  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
1019  engine->config->verbosity);
1020  /* setup */
1021  tzset(); /* for portability */
1022  status = engine_setup(engine);
1023  if (status != ODS_STATUS_OK) {
1024  ods_log_error("[%s] setup failed: %s", engine_str,
1025  ods_status2str(status));
1026  engine->need_to_exit = 1;
1027  if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
1028  /* command handler had not yet been started */
1029  engine->cmdhandler_done = 1;
1030  }
1031  } else {
1032  /* setup ok, mark hsm open */
1033  close_hsm = 1;
1034  }
1035 
1036  /* run */
1037  while (engine->need_to_exit == 0) {
1038  /* update zone list */
1039  lock_basic_lock(&engine->zonelist->zl_lock);
1040  zl_changed = zonelist_update(engine->zonelist,
1041  engine->config->zonelist_filename);
1042  engine->zonelist->just_removed = 0;
1043  engine->zonelist->just_added = 0;
1044  engine->zonelist->just_updated = 0;
1045  lock_basic_unlock(&engine->zonelist->zl_lock);
1046  /* start/reload */
1047  if (engine->need_to_reload) {
1048  ods_log_info("[%s] signer reloading", engine_str);
1049  engine->need_to_reload = 0;
1050  } else {
1051  ods_log_info("[%s] signer started", engine_str);
1052  zl_changed = engine_recover(engine);
1053  }
1054  if (zl_changed == ODS_STATUS_OK ||
1055  zl_changed == ODS_STATUS_UNCHANGED) {
1056  engine_update_zones(engine, zl_changed);
1057  }
1058  engine_run(engine, single_run);
1059  }
1060 
1061  /* shutdown */
1062  ods_log_info("[%s] signer shutdown", engine_str);
1063  if (close_hsm) {
1064  ods_log_verbose("[%s] close hsm", engine_str);
1065  hsm_close();
1066  }
1067  if (!engine->cmdhandler_done) {
1068  engine_stop_xfrhandler(engine);
1069  engine_stop_dnshandler(engine);
1070  engine_stop_cmdhandler(engine);
1071  }
1072 
1073 earlyexit:
1074  if (engine && engine->config) {
1075  if (engine->config->pid_filename) {
1076  (void)unlink(engine->config->pid_filename);
1077  }
1078  if (engine->config->clisock_filename) {
1079  (void)unlink(engine->config->clisock_filename);
1080  }
1081  }
1083  engine_cleanup(engine);
1084  engine = NULL;
1085  ods_log_close();
1086  xmlCleanupParser();
1087  xmlCleanupGlobals();
1088  xmlCleanupThreads();
1089  return;
1090 }
1091 
1092 
1097 void
1099 {
1100  size_t i = 0;
1101  allocator_type* allocator;
1102  cond_basic_type signal_cond;
1103  lock_basic_type signal_lock;
1104  if (!engine) {
1105  return;
1106  }
1107  allocator = engine->allocator;
1108  signal_cond = engine->signal_cond;
1109  signal_lock = engine->signal_lock;
1110  if (engine->workers && engine->config) {
1111  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
1112  worker_cleanup(engine->workers[i]);
1113  }
1114  allocator_deallocate(allocator, (void*) engine->workers);
1115  }
1116  if (engine->drudgers && engine->config) {
1117  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
1118  worker_cleanup(engine->drudgers[i]);
1119  }
1120  allocator_deallocate(allocator, (void*) engine->drudgers);
1121  }
1122  zonelist_cleanup(engine->zonelist);
1123  schedule_cleanup(engine->taskq);
1124  fifoq_cleanup(engine->signq);
1125  cmdhandler_cleanup(engine->cmdhandler);
1126  dnshandler_cleanup(engine->dnshandler);
1127  xfrhandler_cleanup(engine->xfrhandler);
1128  engine_config_cleanup(engine->config);
1129  allocator_deallocate(allocator, (void*) engine);
1130  lock_basic_destroy(&signal_lock);
1131  lock_basic_off(&signal_cond);
1132  allocator_cleanup(allocator);
1133  return;
1134 }