OpenDNSSEC-signer  2.0.3
engine.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
32 #include "config.h"
33 #include "daemon/cfg.h"
34 #include "daemon/engine.h"
35 #include "daemon/signal.h"
36 #include "duration.h"
37 #include "file.h"
38 #include "str.h"
39 #include "hsm.h"
40 #include "locks.h"
41 #include "log.h"
42 #include "privdrop.h"
43 #include "status.h"
44 #include "util.h"
45 #include "signer/zonelist.h"
46 #include "wire/tsig.h"
47 #include "libhsm.h"
48 
49 #include <errno.h>
50 #include <libxml/parser.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <strings.h>
56 #include <sys/socket.h>
57 #include <sys/types.h>
58 #include <sys/un.h>
59 #include <time.h>
60 #include <unistd.h>
61 
62 static const char* engine_str = "engine";
63 
64 
69 static engine_type*
70 engine_create(void)
71 {
72  engine_type* engine;
73  CHECKALLOC(engine = (engine_type*) malloc(sizeof(engine_type)));
74  engine->config = NULL;
75  engine->workers = NULL;
76  engine->drudgers = NULL;
77  engine->cmdhandler = NULL;
78  engine->cmdhandler_done = 0;
79  engine->dnshandler = NULL;
80  engine->xfrhandler = NULL;
81  engine->taskq = NULL;
82  engine->signq = NULL;
83  engine->pid = -1;
84  engine->uid = -1;
85  engine->gid = -1;
86  engine->daemonize = 0;
87  engine->need_to_exit = 0;
88  engine->need_to_reload = 0;
89  lock_basic_init(&engine->signal_lock);
90  lock_basic_set(&engine->signal_cond);
91  lock_basic_lock(&engine->signal_lock);
92  engine->signal = SIGNAL_INIT;
93  lock_basic_unlock(&engine->signal_lock);
94  engine->zonelist = zonelist_create();
95  if (!engine->zonelist) {
96  engine_cleanup(engine);
97  return NULL;
98  }
99  engine->taskq = schedule_create();
100  if (!engine->taskq) {
101  engine_cleanup(engine);
102  return NULL;
103  }
104  engine->signq = fifoq_create();
105  if (!engine->signq) {
106  engine_cleanup(engine);
107  return NULL;
108  }
109  return engine;
110 }
111 
112 
118 static void*
119 cmdhandler_thread_start(void* arg)
120 {
121  cmdhandler_type* cmd = (cmdhandler_type*) arg;
122  ods_thread_blocksigs();
123  cmdhandler_start(cmd);
124  return NULL;
125 }
126 
127 static void
128 engine_start_cmdhandler(engine_type* engine)
129 {
130  ods_log_assert(engine);
131  ods_log_debug("[%s] start command handler", engine_str);
132  engine->cmdhandler->engine = engine;
133  ods_thread_create(&engine->cmdhandler->thread_id,
134  cmdhandler_thread_start, engine->cmdhandler);
135 }
136 
141 static int
142 self_pipe_trick(engine_type* engine)
143 {
144  int sockfd, ret;
145  struct sockaddr_un servaddr;
146  const char* servsock_filename = ODS_SE_SOCKFILE;
147  ods_log_assert(engine);
148  ods_log_assert(engine->cmdhandler);
149  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
150  if (sockfd < 0) {
151  ods_log_error("[%s] unable to connect to command handler: "
152  "socket() failed (%s)", engine_str, strerror(errno));
153  return 1;
154  } else {
155  bzero(&servaddr, sizeof(servaddr));
156  servaddr.sun_family = AF_UNIX;
157  strncpy(servaddr.sun_path, servsock_filename, sizeof(servaddr.sun_path)-1);
158  ret = connect(sockfd, (const struct sockaddr*) &servaddr,
159  sizeof(servaddr));
160  if (ret != 0) {
161  ods_log_error("[%s] unable to connect to command handler: "
162  "connect() failed (%s)", engine_str, strerror(errno));
163  close(sockfd);
164  return 1;
165  } else {
166  /* self-pipe trick */
167  ods_writen(sockfd, "", 1);
168  close(sockfd);
169  }
170  }
171  return 0;
172 }
177 static void
178 engine_stop_cmdhandler(engine_type* engine)
179 {
180  ods_log_assert(engine);
181  if (!engine->cmdhandler || engine->cmdhandler_done) {
182  return;
183  }
184  ods_log_debug("[%s] stop command handler", engine_str);
185  engine->cmdhandler->need_to_exit = 1;
186  if (self_pipe_trick(engine) == 0) {
187  while (!engine->cmdhandler_done) {
188  ods_log_debug("[%s] waiting for command handler to exit...",
189  engine_str);
190  sleep(1);
191  }
192  } else {
193  ods_log_error("[%s] command handler self pipe trick failed, "
194  "unclean shutdown", engine_str);
195  }
196 }
197 
198 
203 static void*
204 dnshandler_thread_start(void* arg)
205 {
206  dnshandler_type* dnshandler = (dnshandler_type*) arg;
207  dnshandler_start(dnshandler);
208  return NULL;
209 }
210 static void
211 engine_start_dnshandler(engine_type* engine)
212 {
213  if (!engine || !engine->dnshandler) {
214  return;
215  }
216  ods_log_debug("[%s] start dnshandler", engine_str);
217  engine->dnshandler->engine = engine;
218  ods_thread_create(&engine->dnshandler->thread_id,
219  dnshandler_thread_start, engine->dnshandler);
220 }
221 static void
222 engine_stop_dnshandler(engine_type* engine)
223 {
224  if (!engine || !engine->dnshandler || !engine->dnshandler->thread_id) {
225  return;
226  }
227  ods_log_debug("[%s] stop dnshandler", engine_str);
228  engine->dnshandler->need_to_exit = 1;
229  dnshandler_signal(engine->dnshandler);
230  ods_log_debug("[%s] join dnshandler", engine_str);
231  ods_thread_join(engine->dnshandler->thread_id);
232  engine->dnshandler->engine = NULL;
233 }
234 
235 
240 static void*
241 xfrhandler_thread_start(void* arg)
242 {
243  xfrhandler_type* xfrhandler = (xfrhandler_type*) arg;
244  xfrhandler_start(xfrhandler);
245  return NULL;
246 }
247 static void
248 engine_start_xfrhandler(engine_type* engine)
249 {
250  if (!engine || !engine->xfrhandler) {
251  return;
252  }
253  ods_log_debug("[%s] start xfrhandler", engine_str);
254  engine->xfrhandler->engine = engine;
255  /* This might be the wrong place to mark the xfrhandler started but
256  * if its isn't done here we might try to shutdown and stop it before
257  * it has marked itself started
258  */
259  engine->xfrhandler->started = 1;
260  ods_thread_create(&engine->xfrhandler->thread_id,
261  xfrhandler_thread_start, engine->xfrhandler);
262 }
263 static void
264 engine_stop_xfrhandler(engine_type* engine)
265 {
266  if (!engine || !engine->xfrhandler) {
267  return;
268  }
269  ods_log_debug("[%s] stop xfrhandler", engine_str);
270  engine->xfrhandler->need_to_exit = 1;
271  xfrhandler_signal(engine->xfrhandler);
272  ods_log_debug("[%s] join xfrhandler", engine_str);
273  if (engine->xfrhandler->started) {
274  ods_thread_join(engine->xfrhandler->thread_id);
275  engine->xfrhandler->started = 0;
276  }
277  engine->xfrhandler->engine = NULL;
278 }
279 
280 
285 static ods_status
286 engine_privdrop(engine_type* engine)
287 {
288  ods_status status = ODS_STATUS_OK;
289  uid_t uid = -1;
290  gid_t gid = -1;
291  ods_log_assert(engine);
292  ods_log_assert(engine->config);
293  ods_log_debug("[%s] drop privileges", engine_str);
294  if (engine->config->username && engine->config->group) {
295  ods_log_verbose("[%s] drop privileges to user %s, group %s",
296  engine_str, engine->config->username, engine->config->group);
297  } else if (engine->config->username) {
298  ods_log_verbose("[%s] drop privileges to user %s", engine_str,
299  engine->config->username);
300  } else if (engine->config->group) {
301  ods_log_verbose("[%s] drop privileges to group %s", engine_str,
302  engine->config->group);
303  }
304  if (engine->config->chroot) {
305  ods_log_verbose("[%s] chroot to %s", engine_str,
306  engine->config->chroot);
307  }
308  status = privdrop(engine->config->username, engine->config->group,
309  engine->config->chroot, &uid, &gid);
310  engine->uid = uid;
311  engine->gid = gid;
312  privclose(engine->config->username, engine->config->group);
313  return status;
314 }
315 
316 
321 static void
322 engine_create_workers(engine_type* engine)
323 {
324  size_t i = 0;
325  ods_log_assert(engine);
326  ods_log_assert(engine->config);
327  CHECKALLOC(engine->workers = (worker_type**) malloc(((size_t)engine->config->num_worker_threads) * sizeof(worker_type*)));
328  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
329  engine->workers[i] = worker_create(i, WORKER_WORKER);
330  }
331 }
332 static void
333 engine_create_drudgers(engine_type* engine)
334 {
335  size_t i = 0;
336  ods_log_assert(engine);
337  ods_log_assert(engine->config);
338  CHECKALLOC(engine->drudgers = (worker_type**) malloc(((size_t)engine->config->num_signer_threads) * sizeof(worker_type*)));
339  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
340  engine->drudgers[i] = worker_create(i, WORKER_DRUDGER);
341  }
342 }
343 static void*
344 worker_thread_start(void* arg)
345 {
346  worker_type* worker = (worker_type*) arg;
347  ods_thread_blocksigs();
348  worker_start(worker);
349  return NULL;
350 }
351 static void
352 engine_start_workers(engine_type* engine)
353 {
354  size_t i = 0;
355  ods_log_assert(engine);
356  ods_log_assert(engine->config);
357  ods_log_debug("[%s] start workers", engine_str);
358  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
359  engine->workers[i]->need_to_exit = 0;
360  engine->workers[i]->engine = (void*) engine;
361  ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
362  engine->workers[i]);
363  }
364 }
365 void
367 {
368  size_t i = 0;
369  ods_log_assert(engine);
370  ods_log_assert(engine->config);
371  ods_log_debug("[%s] start drudgers", engine_str);
372  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
373  engine->drudgers[i]->need_to_exit = 0;
374  engine->drudgers[i]->engine = (void*) engine;
375  ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
376  engine->drudgers[i]);
377  }
378 }
379 static void
380 engine_stop_workers(engine_type* engine)
381 {
382  int i = 0;
383  ods_log_assert(engine);
384  ods_log_assert(engine->config);
385  ods_log_debug("[%s] stop workers", engine_str);
386  /* tell them to exit and wake up sleepyheads */
387  for (i=0; i < engine->config->num_worker_threads; i++) {
388  engine->workers[i]->need_to_exit = 1;
389  worker_wakeup(engine->workers[i]);
390  }
391  ods_log_debug("[%s] notify workers", engine_str);
392  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull);
393  /* head count */
394  for (i=0; i < engine->config->num_worker_threads; i++) {
395  ods_log_debug("[%s] join worker %d", engine_str, i+1);
396  ods_thread_join(engine->workers[i]->thread_id);
397  engine->workers[i]->engine = NULL;
398  }
399 }
400 void
402 {
403  int i = 0;
404  ods_log_assert(engine);
405  ods_log_assert(engine->config);
406  ods_log_debug("[%s] stop drudgers", engine_str);
407  /* tell them to exit and wake up sleepyheads */
408  for (i=0; i < engine->config->num_signer_threads; i++) {
409  engine->drudgers[i]->need_to_exit = 1;
410  }
411  ods_log_debug("[%s] notify drudgers", engine_str);
412  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
413  /* head count */
414  for (i=0; i < engine->config->num_signer_threads; i++) {
415  ods_log_debug("[%s] join drudger %d", engine_str, i+1);
416  ods_thread_join(engine->drudgers[i]->thread_id);
417  engine->drudgers[i]->engine = NULL;
418  }
419 }
420 
421 
426 void
428 {
429  size_t i = 0;
430  ods_log_assert(engine);
431  ods_log_assert(engine->config);
432  ods_log_debug("[%s] wake up workers", engine_str);
433  /* wake up sleepyheads */
434  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
435  worker_wakeup(engine->workers[i]);
436  }
437 }
438 
439 
444 static ods_status
445 engine_setup(engine_type* engine)
446 {
447  ods_status status = ODS_STATUS_OK;
448  struct sigaction action;
449  int sockets[2] = {0,0};
450 
451  ods_log_debug("[%s] setup signer engine", engine_str);
452  if (!engine || !engine->config) {
453  return ODS_STATUS_ASSERT_ERR;
454  }
455  /* set edns */
457 
458  /* create command handler (before chowning socket file) */
460  if (!engine->cmdhandler) {
461  return ODS_STATUS_CMDHANDLER_ERR;
462  }
463  engine->dnshandler = dnshandler_create(engine->config->interfaces);
464  engine->xfrhandler = xfrhandler_create();
465  if (!engine->xfrhandler) {
466  return ODS_STATUS_XFRHANDLER_ERR;
467  }
468  if (engine->dnshandler) {
469  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == -1) {
470  return ODS_STATUS_XFRHANDLER_ERR;
471  }
472  engine->xfrhandler->dnshandler.fd = sockets[0];
473  engine->dnshandler->xfrhandler.fd = sockets[1];
474  status = dnshandler_listen(engine->dnshandler);
475  if (status != ODS_STATUS_OK) {
476  ods_log_error("[%s] setup: unable to listen to sockets (%s)",
477  engine_str, ods_status2str(status));
478  return ODS_STATUS_XFRHANDLER_ERR;
479  }
480  }
481  /* privdrop */
482  engine->uid = privuid(engine->config->username);
483  engine->gid = privgid(engine->config->group);
484  /* TODO: does piddir exists? */
485  /* remove the chown stuff: piddir? */
486  ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
487  ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
488  ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
489  if (engine->config->log_filename && !engine->config->use_syslog) {
490  ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
491  }
492  if (engine->config->working_dir &&
493  chdir(engine->config->working_dir) != 0) {
494  ods_log_error("[%s] setup: unable to chdir to %s (%s)", engine_str,
495  engine->config->working_dir, strerror(errno));
496  return ODS_STATUS_CHDIR_ERR;
497  }
498  if (engine_privdrop(engine) != ODS_STATUS_OK) {
499  return ODS_STATUS_PRIVDROP_ERR;
500  }
501  /* daemonize */
502  if (engine->daemonize) {
503  switch ((engine->pid = fork())) {
504  case -1: /* error */
505  ods_log_error("[%s] setup: unable to fork daemon (%s)",
506  engine_str, strerror(errno));
507  return ODS_STATUS_FORK_ERR;
508  case 0: /* child */
509  break;
510  default: /* parent */
511  engine_cleanup(engine);
512  engine = NULL;
513  xmlCleanupParser();
514  xmlCleanupGlobals();
515  xmlCleanupThreads();
516  exit(0);
517  }
518  if (setsid() == -1) {
519  ods_log_error("[%s] setup: unable to setsid daemon (%s)",
520  engine_str, strerror(errno));
521  return ODS_STATUS_SETSID_ERR;
522  }
523  }
524  engine->pid = getpid();
525  /* write pidfile */
526  if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
527  return ODS_STATUS_WRITE_PIDFILE_ERR;
528  }
529  /* setup done */
530  ods_log_verbose("[%s] running as pid %lu", engine_str,
531  (unsigned long) engine->pid);
532  /* catch signals */
533  signal_set_engine(engine);
534  action.sa_handler = (void (*)(int))signal_handler;
535  sigfillset(&action.sa_mask);
536  action.sa_flags = 0;
537  sigaction(SIGTERM, &action, NULL);
538  sigaction(SIGHUP, &action, NULL);
539  sigaction(SIGINT, &action, NULL);
540  sigaction(SIGILL, &action, NULL);
541  sigaction(SIGUSR1, &action, NULL);
542  sigaction(SIGALRM, &action, NULL);
543  sigaction(SIGCHLD, &action, NULL);
544  action.sa_handler = SIG_IGN;
545  sigaction(SIGPIPE, &action, NULL);
546  /* create workers/drudgers */
547  engine_create_workers(engine);
548  engine_create_drudgers(engine);
549  /* start cmd/dns/xfr handlers */
550  engine_start_cmdhandler(engine);
551  engine_start_dnshandler(engine);
552  engine_start_xfrhandler(engine);
554  return ODS_STATUS_OK;
555 }
556 
557 
562 static int
563 engine_all_zones_processed(engine_type* engine)
564 {
565  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
566  zone_type* zone = NULL;
567 
568  ods_log_assert(engine);
569  ods_log_assert(engine->zonelist);
570  ods_log_assert(engine->zonelist->zones);
571 
572  node = ldns_rbtree_first(engine->zonelist->zones);
573  while (node && node != LDNS_RBTREE_NULL) {
574  zone = (zone_type*) node->key;
575  ods_log_assert(zone);
576  ods_log_assert(zone->db);
577  if (!zone->db->is_processed) {
578  return 0;
579  }
580  node = ldns_rbtree_next(node);
581  }
582  return 1;
583 }
584 
585 
590 static void
591 engine_run(engine_type* engine, int single_run)
592 {
593  if (!engine) {
594  return;
595  }
596  engine_start_workers(engine);
597  engine_start_drudgers(engine);
598 
599  lock_basic_lock(&engine->signal_lock);
600  engine->signal = SIGNAL_RUN;
601  lock_basic_unlock(&engine->signal_lock);
602 
603  while (!engine->need_to_exit && !engine->need_to_reload) {
604  lock_basic_lock(&engine->signal_lock);
605  engine->signal = signal_capture(engine->signal);
606  switch (engine->signal) {
607  case SIGNAL_RUN:
608  ods_log_assert(1);
609  break;
610  case SIGNAL_RELOAD:
611  ods_log_error("signer instructed to reload due to explicit signal");
612  engine->need_to_reload = 1;
613  break;
614  case SIGNAL_SHUTDOWN:
615  engine->need_to_exit = 1;
616  break;
617  default:
618  ods_log_warning("[%s] invalid signal %d captured, "
619  "keep running", engine_str, (int)engine->signal);
620  engine->signal = SIGNAL_RUN;
621  break;
622  }
623  lock_basic_unlock(&engine->signal_lock);
624 
625  if (single_run) {
626  engine->need_to_exit = engine_all_zones_processed(engine);
627  }
628  lock_basic_lock(&engine->signal_lock);
629  if (engine->signal == SIGNAL_RUN && !single_run) {
630  ods_log_debug("[%s] taking a break", engine_str);
631  lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
632  }
633  lock_basic_unlock(&engine->signal_lock);
634  }
635  ods_log_debug("[%s] signer halted", engine_str);
636  engine_stop_drudgers(engine);
637  engine_stop_workers(engine);
638 }
639 
640 
645 static void
646 set_notify_ns(zone_type* zone, const char* cmd)
647 {
648  const char* str = NULL;
649  const char* str2 = NULL;
650  char* token = NULL;
651  ods_log_assert(cmd);
652  ods_log_assert(zone);
653  ods_log_assert(zone->name);
654  ods_log_assert(zone->adoutbound);
655  if (zone->adoutbound->type == ADAPTER_FILE) {
656  str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
657  if (!str) {
658  ods_log_error("[%s] unable to set notify ns: replace zonefile failed",
659  engine_str);
660  }
661  str2 = ods_replace(str, "%zone", zone->name);
662  free((void*)str);
663  } else {
664  str2 = ods_replace(cmd, "%zone", zone->name);
665  }
666  if (str2) {
667  ods_str_trim((char*) str2, 1);
668  str = str2;
669  if (*str) {
670  token = NULL;
671  while ((token = strtok((char*) str, " "))) {
672  if (*token) {
673  ods_str_list_add(&zone->notify_args, token);
674  }
675  str = NULL;
676  }
677  }
678  zone->notify_command = (char*) str2;
679  zone->notify_ns = zone->notify_args[0];
680  ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
681  } else {
682  ods_log_error("[%s] unable to set notify ns: replace zone failed",
683  engine_str);
684  }
685 }
686 
687 
692 static int
693 dnsconfig_zone(engine_type* engine, zone_type* zone)
694 {
695  int numdns = 0;
696  ods_log_assert(engine);
697  ods_log_assert(engine->xfrhandler);
698  ods_log_assert(engine->xfrhandler->netio);
699  ods_log_assert(zone);
700  ods_log_assert(zone->adinbound);
701  ods_log_assert(zone->adoutbound);
702  ods_log_assert(zone->name);
703 
704  if (zone->adinbound->type == ADAPTER_DNS) {
705  /* zone transfer handler */
706  if (!zone->xfrd) {
707  ods_log_debug("[%s] add transfer handler for zone %s",
708  engine_str, zone->name);
709  zone->xfrd = xfrd_create((void*) engine->xfrhandler,
710  (void*) zone);
711  ods_log_assert(zone->xfrd);
713  &zone->xfrd->handler);
714  } else if (!zone->xfrd->serial_disk_acquired) {
715  xfrd_set_timer_now(zone->xfrd);
716  }
717  numdns++;
718  } else if (zone->xfrd) {
720  &zone->xfrd->handler);
721  xfrd_cleanup(zone->xfrd, 0);
722  zone->xfrd = NULL;
723  }
724  if (zone->adoutbound->type == ADAPTER_DNS) {
725  /* notify handler */
726  if (!zone->notify) {
727  ods_log_debug("[%s] add notify handler for zone %s",
728  engine_str, zone->name);
729  zone->notify = notify_create((void*) engine->xfrhandler,
730  (void*) zone);
731  ods_log_assert(zone->notify);
733  &zone->notify->handler);
734  }
735  numdns++;
736  } else if (zone->notify) {
738  &zone->notify->handler);
739  notify_cleanup(zone->notify);
740  zone->notify = NULL;
741  }
742  return numdns;
743 }
744 
745 
750 void
751 engine_update_zones(engine_type* engine, ods_status zl_changed)
752 {
753  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
754  zone_type* zone = NULL;
755  zone_type* delzone = NULL;
756  task_type* task = NULL;
757  ods_status status = ODS_STATUS_OK;
758  unsigned wake_up = 0;
759  int warnings = 0;
760  time_t now = 0;
761 
762  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
763  return;
764  }
765  now = time_now();
766 
767  ods_log_debug("[%s] commit zone list changes", engine_str);
768  lock_basic_lock(&engine->zonelist->zl_lock);
769  node = ldns_rbtree_first(engine->zonelist->zones);
770  while (node && node != LDNS_RBTREE_NULL) {
771  zone = (zone_type*) node->data;
772  task = NULL; /* reset task */
773 
774  if (zone->zl_status == ZONE_ZL_REMOVED) {
775  node = ldns_rbtree_next(node);
776  lock_basic_lock(&zone->zone_lock);
777  delzone = zonelist_del_zone(engine->zonelist, zone);
778  if (delzone) {
779  lock_basic_lock(&engine->taskq->schedule_lock);
780  task = unschedule_task(engine->taskq,
781  (task_type*) zone->task);
782  lock_basic_unlock(&engine->taskq->schedule_lock);
783  }
784  task_cleanup(task);
785  task = NULL;
786  lock_basic_unlock(&zone->zone_lock);
788  &zone->xfrd->handler);
789  zone_cleanup(zone);
790  zone = NULL;
791  continue;
792  } else if (zone->zl_status == ZONE_ZL_ADDED) {
793  lock_basic_lock(&zone->zone_lock);
794  ods_log_assert(!zone->task);
795  /* set notify nameserver command */
796  if (engine->config->notify_command && !zone->notify_ns) {
797  set_notify_ns(zone, engine->config->notify_command);
798  }
799  /* create task */
800  task = task_create(TASK_SIGNCONF, now, zone);
801  lock_basic_unlock(&zone->zone_lock);
802  if (!task) {
803  ods_log_crit("[%s] unable to create task for zone %s: "
804  "task_create() failed", engine_str, zone->name);
805  node = ldns_rbtree_next(node);
806  continue;
807  }
808  }
809  /* load adapter config */
810  status = adapter_load_config(zone->adinbound);
811  if (status != ODS_STATUS_OK) {
812  ods_log_error("[%s] unable to load config for inbound adapter "
813  "for zone %s: %s", engine_str, zone->name,
814  ods_status2str(status));
815  }
816  status = adapter_load_config(zone->adoutbound);
817  if (status != ODS_STATUS_OK) {
818  ods_log_error("[%s] unable to load config for outbound adapter "
819  "for zone %s: %s", engine_str, zone->name,
820  ods_status2str(status));
821  }
822  /* for dns adapters */
823  warnings += dnsconfig_zone(engine, zone);
824 
825  if (zone->zl_status == ZONE_ZL_ADDED) {
826  ods_log_assert(task);
827  lock_basic_lock(&zone->zone_lock);
828  zone->task = task;
829  lock_basic_unlock(&zone->zone_lock);
830  /* TODO: task is reachable from other threads by means of
831  * zone->task. To fix this we need to nest the locks. But
832  * first investigate any possible deadlocks. */
833  lock_basic_lock(&engine->taskq->schedule_lock);
834  status = schedule_task(engine->taskq, task, 0);
835  lock_basic_unlock(&engine->taskq->schedule_lock);
836  } else if (zl_changed == ODS_STATUS_OK) {
837  /* always try to update signconf */
838  lock_basic_lock(&zone->zone_lock);
839  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
840  lock_basic_unlock(&zone->zone_lock);
841  }
842  if (status != ODS_STATUS_OK) {
843  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
844  engine_str, zone->name, ods_status2str(status));
845  } else {
846  wake_up = 1;
847  zone->zl_status = ZONE_ZL_OK;
848  }
849  node = ldns_rbtree_next(node);
850  }
851  lock_basic_unlock(&engine->zonelist->zl_lock);
852  if (engine->dnshandler) {
853  ods_log_debug("[%s] forward notify for all zones", engine_str);
855  (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
856  } else if (warnings) {
857  ods_log_warning("[%s] no dnshandler/listener configured, but zones "
858  "are configured with dns adapters: notify and zone transfer "
859  "requests will not work properly", engine_str);
860  }
861  if (wake_up) {
862  engine_wakeup_workers(engine);
863  }
864 }
865 
866 
871 static ods_status
872 engine_recover(engine_type* engine)
873 {
874  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
875  zone_type* zone = NULL;
876  ods_status status = ODS_STATUS_OK;
877  ods_status result = ODS_STATUS_UNCHANGED;
878 
879  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
880  ods_log_error("[%s] cannot recover zones: no engine or zonelist",
881  engine_str);
882  return ODS_STATUS_ERR; /* no need to update zones */
883  }
884  ods_log_assert(engine);
885  ods_log_assert(engine->zonelist);
886  ods_log_assert(engine->zonelist->zones);
887 
888  lock_basic_lock(&engine->zonelist->zl_lock);
889  /* [LOCK] zonelist */
890  node = ldns_rbtree_first(engine->zonelist->zones);
891  while (node && node != LDNS_RBTREE_NULL) {
892  zone = (zone_type*) node->data;
893 
894  ods_log_assert(zone->zl_status == ZONE_ZL_ADDED);
895  lock_basic_lock(&zone->zone_lock);
896  status = zone_recover2(zone);
897  if (status == ODS_STATUS_OK) {
898  ods_log_assert(zone->task);
899  ods_log_assert(zone->db);
900  ods_log_assert(zone->signconf);
901  /* notify nameserver */
902  if (engine->config->notify_command && !zone->notify_ns) {
903  set_notify_ns(zone, engine->config->notify_command);
904  }
905  /* schedule task */
906  lock_basic_lock(&engine->taskq->schedule_lock);
907  /* [LOCK] schedule */
908  status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
909  /* [UNLOCK] schedule */
910  lock_basic_unlock(&engine->taskq->schedule_lock);
911 
912  if (status != ODS_STATUS_OK) {
913  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
914  engine_str, zone->name, ods_status2str(status));
915  task_cleanup((task_type*) zone->task);
916  zone->task = NULL;
917  result = ODS_STATUS_OK; /* will trigger update zones */
918  } else {
919  ods_log_debug("[%s] recovered zone %s", engine_str,
920  zone->name);
921  /* recovery done */
922  zone->zl_status = ZONE_ZL_OK;
923  }
924  } else {
925  if (status != ODS_STATUS_UNCHANGED) {
926  ods_log_warning("[%s] unable to recover zone %s from backup,"
927  " performing full sign", engine_str, zone->name);
928  }
929  result = ODS_STATUS_OK; /* will trigger update zones */
930  }
931  lock_basic_unlock(&zone->zone_lock);
932  node = ldns_rbtree_next(node);
933  }
934  /* [UNLOCK] zonelist */
935  lock_basic_unlock(&engine->zonelist->zl_lock);
936  return result;
937 }
938 
939 
944 int
945 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
946  int info, int single_run)
947 {
948  engine_type* engine = NULL;
949  ods_status zl_changed = ODS_STATUS_UNCHANGED;
950  ods_status status = ODS_STATUS_OK;
951 
952  engine = engine_create();
953  if (!engine) {
954  ods_fatal_exit("[%s] create failed", engine_str);
955  return 1;
956  }
957  engine->daemonize = daemonize;
958 
959  /* config */
960  engine->config = engine_config(cfgfile, cmdline_verbosity);
961  status = engine_config_check(engine->config);
962  if (status != ODS_STATUS_OK) {
963  ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
964  goto earlyexit;
965  }
966  if (info) {
967  engine_config_print(stdout, engine->config); /* for debugging */
968  goto earlyexit;
969  }
970  /* check pidfile */
971  if (!util_check_pidfile(engine->config->pid_filename)) {
972  exit(1);
973  }
974  /* open log */
975  ods_log_init("ods-signerd", engine->config->use_syslog,
976  engine->config->log_filename, engine->config->verbosity);
977  /* setup */
978  status = engine_setup(engine);
979  if (status != ODS_STATUS_OK) {
980  ods_log_error("[%s] setup failed: %s", engine_str,
981  ods_status2str(status));
982  if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
983  /* command handler had not yet been started */
984  engine->cmdhandler_done = 1;
985  }
986  goto earlyexit;
987  }
988 
989  /* run */
990  while (engine->need_to_exit == 0) {
991  /* update zone list */
992  lock_basic_lock(&engine->zonelist->zl_lock);
993  zl_changed = zonelist_update(engine->zonelist,
994  engine->config->zonelist_filename);
995  engine->zonelist->just_removed = 0;
996  engine->zonelist->just_added = 0;
997  engine->zonelist->just_updated = 0;
998  lock_basic_unlock(&engine->zonelist->zl_lock);
999  /* start/reload */
1000  if (engine->need_to_reload) {
1001  ods_log_info("[%s] signer reloading", engine_str);
1002  fifoq_wipe(engine->signq);
1003  engine->need_to_reload = 0;
1004  } else {
1005  ods_log_info("[%s] signer started (version %s), pid %u",
1006  engine_str, PACKAGE_VERSION, engine->pid);
1007  if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
1008  char* error = hsm_get_error(NULL);
1009  if (error != NULL) {
1010  ods_log_error("[%s] %s", "hsm", error);
1011  free(error);
1012  }
1013  ods_log_error("[%s] opening hsm failed (for engine recover)", engine_str);
1014  break;
1015  }
1016  zl_changed = engine_recover(engine);
1017  hsm_close();
1018  }
1019  if (zl_changed == ODS_STATUS_OK ||
1020  zl_changed == ODS_STATUS_UNCHANGED) {
1021  engine_update_zones(engine, zl_changed);
1022  }
1023  if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
1024  char* error = hsm_get_error(NULL);
1025  if (error != NULL) {
1026  ods_log_error("[%s] %s", "hsm", error);
1027  free(error);
1028  }
1029  ods_log_error("[%s] opening hsm failed (for engine run)", engine_str);
1030  break;
1031  }
1032  engine_run(engine, single_run);
1033  hsm_close();
1034  }
1035 
1036  /* shutdown */
1037  ods_log_info("[%s] signer shutdown", engine_str);
1038  engine_stop_cmdhandler(engine);
1039  engine_stop_xfrhandler(engine);
1040  engine_stop_dnshandler(engine);
1041 
1042 earlyexit:
1043  if (engine && engine->config) {
1044  if (engine->config->pid_filename) {
1045  (void)unlink(engine->config->pid_filename);
1046  }
1047  if (engine->config->clisock_filename) {
1048  (void)unlink(engine->config->clisock_filename);
1049  }
1050  }
1052  engine_cleanup(engine);
1053  engine = NULL;
1054 
1055  return 1;
1056 }
1057 
1058 
1063 void
1065 {
1066  size_t i = 0;
1067 
1068  if (!engine) {
1069  return;
1070  }
1071  if (engine->workers && engine->config) {
1072  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
1073  worker_cleanup(engine->workers[i]);
1074  }
1075  free(engine->workers);
1076  }
1077  if (engine->drudgers && engine->config) {
1078  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
1079  worker_cleanup(engine->drudgers[i]);
1080  }
1081  free(engine->drudgers);
1082  }
1083  zonelist_cleanup(engine->zonelist);
1084  schedule_cleanup(engine->taskq);
1085  fifoq_cleanup(engine->signq);
1086  cmdhandler_cleanup(engine->cmdhandler);
1087  dnshandler_cleanup(engine->dnshandler);
1088  xfrhandler_cleanup(engine->xfrhandler);
1089  engine_config_cleanup(engine->config);
1090  lock_basic_destroy(&engine->signal_lock);
1091  lock_basic_off(&engine->signal_cond);
1092  free(engine);
1093 }
edns_data_type edns
Definition: engine.h:66
void engine_config_cleanup(engineconfig_type *config)
Definition: cfg.c:243
void engine_config_print(FILE *out, engineconfig_type *config)
Definition: cfg.c:146
int num_signer_threads
Definition: cfg.h:60
void tsig_handler_cleanup(void)
Definition: tsig.c:135
task_type * task
Definition: zone.h:83
void zone_cleanup(zone_type *zone)
Definition: zone.c:807
#define ODS_SE_NOTIFY_CMD
Definition: dnshandler.h:48
zonelist_type * zonelist
Definition: engine.h:60
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:427
schedule_type * schedule_create()
Definition: schedule.c:48
unsigned need_to_exit
Definition: worker.h:66
void engine_stop_drudgers(engine_type *engine)
Definition: engine.c:401
worker_type * worker_create(int num, worker_id type)
Definition: worker.c:65
int just_updated
Definition: zonelist.h:48
ods_status dnshandler_listen(dnshandler_type *dnshandler)
Definition: dnshandler.c:105
cond_basic_type signal_cond
Definition: engine.h:78
cond_basic_type q_threshold
Definition: fifoq.h:65
ods_status tsig_handler_init()
Definition: tsig.c:116
char * notify_command
Definition: zone.h:63
const char * zonelist_filename
Definition: cfg.h:49
void xfrhandler_cleanup(xfrhandler_type *xfrhandler)
Definition: xfrhandler.c:197
void engine_update_zones(engine_type *engine, ods_status zl_changed)
Definition: engine.c:751
const char * configstr
Definition: adapter.h:60
netio_type * netio
Definition: xfrhandler.h:60
lock_basic_type q_lock
Definition: fifoq.h:64
sig_atomic_t signal
Definition: engine.h:77
ods_status adapter_load_config(adapter_type *adapter)
Definition: adapter.c:99
int engine_start(const char *cfgfile, int cmdline_verbosity, int daemonize, int info, int single_run)
Definition: engine.c:945
unsigned need_to_exit
Definition: xfrhandler.h:72
ods_status zone_recover2(zone_type *zone)
Definition: zone.c:838
ods_status schedule_task(schedule_type *schedule, task_type *task, int log)
Definition: schedule.c:140
void signal_set_engine(void *engine)
Definition: signal.c:51
engine_type * engine
Definition: xfrhandler.h:55
const char * group
Definition: cfg.h:56
ldns_rbtree_t * zones
Definition: zonelist.h:45
void worker_start(worker_type *worker)
Definition: worker.c:743
lock_basic_type zone_lock
Definition: zone.h:86
engine_type * engine
Definition: dnshandler.h:53
ods_thread_type thread_id
Definition: cmdhandler.h:50
adapter_mode type
Definition: adapter.h:58
zone_zl_status zl_status
Definition: zone.h:70
int just_removed
Definition: zonelist.h:49
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:929
void worker_cleanup(worker_type *worker)
Definition: worker.c:837
xfrd_type * xfrd_create(xfrhandler_type *xfrhandler, zone_type *zone)
Definition: xfrd.c:315
netio_handler_type dnshandler
Definition: xfrhandler.h:70
void engine_start_drudgers(engine_type *engine)
Definition: engine.c:366
void notify_cleanup(notify_type *notify)
Definition: notify.c:572
adapter_type * adoutbound
Definition: zone.h:73
#define SIGNAL_RELOAD
Definition: signal.h:41
void netio_add_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:54
void fifoq_cleanup(fifoq_type *q)
Definition: fifoq.c:153
const char * log_filename
Definition: cfg.h:50
lock_basic_type signal_lock
Definition: engine.h:79
const char * clisock_filename
Definition: cfg.h:53
sig_atomic_t signal_capture(sig_atomic_t dflsig)
Definition: signal.c:100
zone_type * zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:238
engineconfig_type * config
Definition: engine.h:57
namedb_type * db
Definition: zone.h:77
int num_worker_threads
Definition: cfg.h:59
void dnshandler_signal(dnshandler_type *dnshandler)
Definition: dnshandler.c:227
xfrhandler_type * xfrhandler_create()
Definition: xfrhandler.c:52
hsm_repository_t * repositories
Definition: cfg.h:47
void xfrhandler_start(xfrhandler_type *xfrhandler)
Definition: xfrhandler.c:109
worker_type ** workers
Definition: engine.h:58
unsigned need_to_exit
Definition: dnshandler.h:59
engineconfig_type * engine_config(const char *cfgfile, int cmdline_verbosity)
Definition: cfg.c:51
unsigned is_processed
Definition: namedb.h:58
void worker_notify_all(lock_basic_type *lock, cond_basic_type *condition)
Definition: worker.c:824
const char * notify_command
Definition: cfg.h:52
worker_type ** drudgers
Definition: engine.h:59
signconf_type * signconf
Definition: zone.h:75
gid_t gid
Definition: engine.h:71
engine_type * engine
Definition: cmdhandler.h:48
adapter_type * adinbound
Definition: zone.h:72
notify_type * notify_create(xfrhandler_type *xfrhandler, zone_type *zone)
Definition: notify.c:100
void task_cleanup(task_type *task)
Definition: task.c:213
void xfrd_cleanup(xfrd_type *xfrd, int backup)
Definition: xfrd.c:2159
void worker_wakeup(worker_type *worker)
Definition: worker.c:805
char ** notify_args
Definition: zone.h:65
void xfrhandler_signal(xfrhandler_type *xfrhandler)
Definition: xfrhandler.c:158
task_type * unschedule_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:185
#define EDNS_MAX_MESSAGE_LEN
Definition: edns.h:47
pid_t pid
Definition: engine.h:69
cmdhandler_type * cmdhandler
Definition: engine.h:63
void netio_remove_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:77
void fifoq_wipe(fifoq_type *q)
Definition: fifoq.c:68
ods_status zone_reschedule_task(zone_type *zone, schedule_type *taskq, task_id what)
Definition: zone.c:186
const char * notify_ns
Definition: zone.h:64
netio_handler_type xfrhandler
Definition: dnshandler.h:58
const char * working_dir
Definition: cfg.h:54
int use_syslog
Definition: cfg.h:58
ods_status engine_config_check(engineconfig_type *config)
Definition: cfg.c:110
fifoq_type * fifoq_create()
Definition: fifoq.c:46
void xfrd_set_timer_now(xfrd_type *xfrd)
Definition: xfrd.c:454
const char * username
Definition: cfg.h:55
void edns_init(edns_data_type *data, uint16_t max_length)
Definition: edns.c:64
listener_type * interfaces
Definition: cfg.h:46
const char * name
Definition: zone.h:67
schedule_type * taskq
Definition: engine.h:61
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:435
cmdhandler_type * cmdhandler_create(const char *filename)
Definition: cmdhandler.c:856
void * signal_handler(sig_atomic_t sig)
Definition: signal.c:62
unsigned started
Definition: xfrhandler.h:73
void engine_cleanup(engine_type *engine)
Definition: engine.c:1064
void schedule_cleanup(schedule_type *schedule)
Definition: schedule.c:304
int daemonize
Definition: engine.h:73
#define SIGNAL_RUN
Definition: signal.h:39
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:345
dnshandler_type * dnshandler_create(listener_type *interfaces)
Definition: dnshandler.c:51
lock_basic_type schedule_lock
Definition: schedule.h:62
int need_to_exit
Definition: engine.h:74
notify_type * notify
Definition: zone.h:81
ods_thread_type thread_id
Definition: dnshandler.h:52
engine_type * engine
Definition: worker.h:54
fifoq_type * signq
Definition: engine.h:62
cond_basic_type q_nonfull
Definition: fifoq.h:66
void dnshandler_start(dnshandler_type *dnshandler)
Definition: dnshandler.c:124
netio_handler_type handler
Definition: notify.h:63
netio_handler_type handler
Definition: xfrd.h:124
ods_thread_type thread_id
Definition: worker.h:53
#define SIGNAL_SHUTDOWN
Definition: signal.h:42
int need_to_reload
Definition: engine.h:75
xfrd_type * xfrd
Definition: zone.h:80
void dnshandler_fwd_notify(dnshandler_type *dnshandler, uint8_t *pkt, size_t len)
Definition: dnshandler.c:240
zonelist_type * zonelist_create()
Definition: zonelist.c:74
const char * pid_filename
Definition: cfg.h:51
const char * chroot
Definition: cfg.h:57
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:995
time_t serial_disk_acquired
Definition: xfrd.h:118
lock_basic_type zl_lock
Definition: zonelist.h:50
ods_thread_type thread_id
Definition: xfrhandler.h:54
int cmdhandler_done
Definition: engine.h:67
task_type * task_create(task_id what, time_t when, void *zone)
Definition: task.c:48
#define SIGNAL_INIT
Definition: signal.h:40
dnshandler_type * dnshandler
Definition: engine.h:64
uid_t uid
Definition: engine.h:70
xfrhandler_type * xfrhandler
Definition: engine.h:65
void dnshandler_cleanup(dnshandler_type *dnshandler)
Definition: dnshandler.c:286