OpenDNSSEC-signer  1.3.9
engine.c
Go to the documentation of this file.
1 /*
2  * $Id: engine.c 6238 2012-04-03 09:53:56Z 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);
105  engine->signal = SIGNAL_INIT;
106  lock_basic_unlock(&engine->signal_lock);
107 
108  engine->zonelist = zonelist_create(engine->allocator);
109  if (!engine->zonelist) {
110  engine_cleanup(engine);
111  return NULL;
112  }
113  engine->taskq = schedule_create(engine->allocator);
114  if (!engine->taskq) {
115  engine_cleanup(engine);
116  return NULL;
117  }
118  engine->signq = fifoq_create(engine->allocator);
119  if (!engine->signq) {
120  engine_cleanup(engine);
121  return NULL;
122  }
123  return engine;
124 }
125 
126 
131 static void*
132 cmdhandler_thread_start(void* arg)
133 {
134  cmdhandler_type* cmd = (cmdhandler_type*) arg;
136  cmdhandler_start(cmd);
137  return NULL;
138 }
139 static void
140 engine_start_cmdhandler(engine_type* engine)
141 {
142  ods_log_assert(engine);
143  ods_log_debug("[%s] start command handler", engine_str);
144  engine->cmdhandler->engine = engine;
146  cmdhandler_thread_start, engine->cmdhandler);
147  return;
148 }
153 static int
154 self_pipe_trick(engine_type* engine)
155 {
156  int sockfd, ret;
157  struct sockaddr_un servaddr;
158  const char* servsock_filename = ODS_SE_SOCKFILE;
159 
160  ods_log_assert(engine);
161  ods_log_assert(engine->cmdhandler);
162 
163  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
164  if (sockfd < 0) {
165  ods_log_error("[%s] cannot connect to command handler: "
166  "socket() failed: %s\n", engine_str, strerror(errno));
167  return 1;
168  } else {
169  bzero(&servaddr, sizeof(servaddr));
170  servaddr.sun_family = AF_UNIX;
171  strncpy(servaddr.sun_path, servsock_filename,
172  sizeof(servaddr.sun_path) - 1);
173 
174  ret = connect(sockfd, (const struct sockaddr*) &servaddr,
175  sizeof(servaddr));
176  if (ret != 0) {
177  ods_log_error("[%s] cannot connect to command handler: "
178  "connect() failed: %s\n", engine_str, strerror(errno));
179  close(sockfd);
180  return 1;
181  } else {
182  /* self-pipe trick */
183  ods_writen(sockfd, "", 1);
184  close(sockfd);
185  }
186  }
187  return 0;
188 }
193 static void
194 engine_stop_cmdhandler(engine_type* engine)
195 {
196  ods_log_assert(engine);
197  if (!engine->cmdhandler) {
198  return;
199  }
200  ods_log_debug("[%s] stop command handler", engine_str);
201  engine->cmdhandler->need_to_exit = 1;
202  if (self_pipe_trick(engine) == 0) {
203  while (!engine->cmdhandler_done) {
204  ods_log_debug("[%s] waiting for command handler to exit...",
205  engine_str);
206  sleep(1);
207  }
208  } else {
209  ods_log_error("[%s] command handler self pipe trick failed, "
210  "unclean shutdown", engine_str);
211  }
212  return;
213 }
214 
215 
220 static ods_status
221 engine_privdrop(engine_type* engine)
222 {
223  ods_status status = ODS_STATUS_OK;
224  uid_t uid = -1;
225  gid_t gid = -1;
226 
227  ods_log_assert(engine);
228  ods_log_assert(engine->config);
229  ods_log_debug("[%s] drop privileges", engine_str);
230 
231  if (engine->config->username && engine->config->group) {
232  ods_log_verbose("[%s] drop privileges to user %s, group %s",
233  engine_str, engine->config->username, engine->config->group);
234  } else if (engine->config->username) {
235  ods_log_verbose("[%s] drop privileges to user %s", engine_str,
236  engine->config->username);
237  } else if (engine->config->group) {
238  ods_log_verbose("[%s] drop privileges to group %s", engine_str,
239  engine->config->group);
240  }
241  if (engine->config->chroot) {
242  ods_log_verbose("[%s] chroot to %s", engine_str,
243  engine->config->chroot);
244  }
245  status = privdrop(engine->config->username, engine->config->group,
246  engine->config->chroot, &uid, &gid);
247  engine->uid = uid;
248  engine->gid = gid;
249  privclose(engine->config->username, engine->config->group);
250  return status;
251 }
252 
253 
258 static void
259 engine_create_workers(engine_type* engine)
260 {
261  size_t i = 0;
262  ods_log_assert(engine);
263  ods_log_assert(engine->config);
264  ods_log_assert(engine->allocator);
265  engine->workers = (worker_type**) allocator_alloc(engine->allocator,
266  ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
267  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
268  engine->workers[i] = worker_create(engine->allocator, i,
269  WORKER_WORKER);
270  }
271  return;
272 }
273 static void
274 engine_create_drudgers(engine_type* engine)
275 {
276  size_t i = 0;
277  ods_log_assert(engine);
278  ods_log_assert(engine->config);
279  ods_log_assert(engine->allocator);
280  engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
281  ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
282  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
283  engine->drudgers[i] = worker_create(engine->allocator, i,
285  }
286  return;
287 }
288 static void*
289 worker_thread_start(void* arg)
290 {
291  worker_type* worker = (worker_type*) arg;
293  worker_start(worker);
294  return NULL;
295 }
296 static void
297 engine_start_workers(engine_type* engine)
298 {
299  size_t i = 0;
300 
301  ods_log_assert(engine);
302  ods_log_assert(engine->config);
303  ods_log_debug("[%s] start workers", engine_str);
304  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
305  engine->workers[i]->need_to_exit = 0;
306  engine->workers[i]->engine = (struct engine_struct*) engine;
307  ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
308  engine->workers[i]);
309  }
310  return;
311 }
312 void
314 {
315  size_t i = 0;
316 
317  ods_log_assert(engine);
318  ods_log_assert(engine->config);
319  ods_log_debug("[%s] start drudgers", engine_str);
320  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
321  engine->drudgers[i]->need_to_exit = 0;
322  engine->drudgers[i]->engine = (struct engine_struct*) engine;
323  ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
324  engine->drudgers[i]);
325  }
326  return;
327 }
328 static void
329 engine_stop_workers(engine_type* engine)
330 {
331  size_t i = 0;
332 
333  ods_log_assert(engine);
334  ods_log_assert(engine->config);
335  ods_log_debug("[%s] stop workers", engine_str);
336  /* tell them to exit and wake up sleepyheads */
337  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
338  engine->workers[i]->need_to_exit = 1;
339  worker_wakeup(engine->workers[i]);
340  }
341  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull);
342  /* head count */
343  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
344  ods_log_debug("[%s] join worker %i", engine_str, i+1);
345  ods_thread_join(engine->workers[i]->thread_id);
346  engine->workers[i]->engine = NULL;
347  }
348  return;
349 }
350 void
352 {
353  size_t i = 0;
354 
355  ods_log_assert(engine);
356  ods_log_assert(engine->config);
357  ods_log_debug("[%s] stop drudgers", engine_str);
358  /* tell them to exit and wake up sleepyheads */
359  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
360  engine->drudgers[i]->need_to_exit = 1;
361  }
362  worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
363 
364  /* head count */
365  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
366  ods_log_debug("[%s] join drudger %i", engine_str, i+1);
367  ods_thread_join(engine->drudgers[i]->thread_id);
368  engine->drudgers[i]->engine = NULL;
369  }
370  return;
371 }
372 
373 
378 void
380 {
381  size_t i = 0;
382 
383  ods_log_assert(engine);
384  ods_log_assert(engine->config);
385  ods_log_debug("[%s] wake up workers", engine_str);
386  /* wake up sleepyheads */
387  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
388  worker_wakeup(engine->workers[i]);
389  }
390  return;
391 }
392 
393 
398 static int
399 start_zonefetcher(engine_type* engine)
400 {
401  pid_t zfpid = 0;
402  int result = 0;
403  char* zf_filename = NULL;
404  char* zl_filename = NULL;
405  char* log_filename = NULL;
406  char* grp = NULL;
407  char* usr = NULL;
408  char* chrt = NULL;
409  int use_syslog = 0;
410  int verbosity = 0;
411 
412  ods_log_assert(engine);
413  ods_log_assert(engine->config);
414 
415  if (!engine->config->zonefetch_filename) {
416  /* zone fetcher disabled */
417  return 0;
418  }
419 
420  switch ((zfpid = fork())) {
421  case -1: /* error */
422  ods_log_error("failed to fork zone fetcher: %s",
423  strerror(errno));
424  return 1;
425  case 0: /* child */
426  break;
427  default: /* parent */
428  engine->zfpid = zfpid;
429  return 0;
430  }
431 
432  if (setsid() == -1) {
433  ods_log_error("failed to setsid zone fetcher: %s",
434  strerror(errno));
435  return 1;
436  }
437 
438  ods_log_verbose("zone fetcher running as pid %lu",
439  (unsigned long) getpid());
440 
441  if (engine->config->zonefetch_filename) {
442  zf_filename = strdup(engine->config->zonefetch_filename);
443  }
444  if (engine->config->zonelist_filename) {
445  zl_filename = strdup(engine->config->zonelist_filename);
446  }
447  if (engine->config->group) {
448  grp = strdup(engine->config->group);
449  }
450  if (engine->config->username) {
451  usr = strdup(engine->config->username);
452  }
453  if (engine->config->chroot) {
454  chrt = strdup(engine->config->chroot);
455  }
456  if (engine->config->log_filename) {
457  log_filename = strdup(engine->config->log_filename);
458  }
459  use_syslog = engine->config->use_syslog;
460  verbosity = engine->config->verbosity;
461 
462  result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
463  chrt, log_filename, use_syslog, verbosity);
464 
465  ods_log_verbose("zone fetcher done", result);
466  if (zf_filename) { free((void*)zf_filename); }
467  if (zl_filename) { free((void*)zl_filename); }
468  if (grp) { free((void*)grp); }
469  if (usr) { free((void*)usr); }
470  if (chrt) { free((void*)chrt); }
471  if (log_filename) { free((void*)log_filename); }
472 
473  engine_cleanup(engine);
474  engine = NULL;
475  ods_log_close();
476  xmlCleanupParser();
477  xmlCleanupGlobals();
478  xmlCleanupThreads();
479  exit(result);
480 
481  return 0;
482 }
483 
484 
489 static void
490 reload_zonefetcher(engine_type* engine)
491 {
492  int result = 0;
493 
494  ods_log_assert(engine);
495  ods_log_assert(engine->config);
496 
497  if (engine->config->zonefetch_filename) {
498  if (engine->zfpid > 0) {
499  result = kill(engine->zfpid, SIGHUP);
500  if (result == -1) {
501  ods_log_error("cannot reload zone fetcher: %s",
502  strerror(errno));
503  } else {
504  ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
505  }
506  } else {
507  ods_log_error("cannot reload zone fetcher: process id unknown");
508  }
509  }
510  return;
511 }
512 
513 
518 static void
519 stop_zonefetcher(engine_type* engine)
520 {
521  int result = 0;
522 
523  ods_log_assert(engine);
524  ods_log_assert(engine->config);
525 
526  if (engine->config->zonefetch_filename) {
527  if (engine->zfpid > 0) {
528  result = kill(engine->zfpid, SIGTERM);
529  if (result == -1) {
530  ods_log_error("cannot stop zone fetcher: %s", strerror(errno));
531  } else {
532  ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
533  }
534  engine->zfpid = -1;
535  } else {
536  ods_log_error("cannot stop zone fetcher: process id unknown");
537  }
538  }
539  return;
540 }
541 
542 
547 static ods_status
548 engine_init_adapters(engine_type* engine)
549 {
550  size_t i = 0;
551  ods_status status = ODS_STATUS_OK;
552 
553  ods_log_assert(engine);
554  ods_log_assert(engine->config);
555  ods_log_debug("[%s] initialize adapters", engine_str);
556  for (i=0; i < (size_t) engine->config->num_adapters; i++) {
557  status = adapter_init(engine->config->adapters[i]);
558  if (status != ODS_STATUS_OK) {
559  return status;
560  }
561  }
562  return status;
563 }
564 
565 
570 static ods_status
571 engine_setup(engine_type* engine)
572 {
573  struct sigaction action;
574  int result = 0;
575  ods_status status = ODS_STATUS_OK;
576 
577  ods_log_debug("[%s] signer setup", engine_str);
578  if (!engine || !engine->config) {
579  return ODS_STATUS_ASSERT_ERR;
580  }
581 
582  /* create command handler (before chowning socket file) */
583  engine->cmdhandler = cmdhandler_create(engine->allocator,
584  engine->config->clisock_filename);
585  if (!engine->cmdhandler) {
586  ods_log_error("[%s] create command handler to %s failed",
587  engine_str, engine->config->clisock_filename);
589  }
590 
591  /* fork of fetcher */
592  if (start_zonefetcher(engine) != 0) {
593  ods_log_error("[%s] cannot start zonefetcher", engine_str);
594  return ODS_STATUS_ERR;
595  }
596 
597  /* initialize adapters */
598  status = engine_init_adapters(engine);
599  if (status != ODS_STATUS_OK) {
600  ods_log_error("[%s] initializing adapters failed", engine_str);
601  return status;
602  }
603 
604  /* privdrop */
605  engine->uid = privuid(engine->config->username);
606  engine->gid = privgid(engine->config->group);
607  /* TODO: does piddir exists? */
608  /* remove the chown stuff: piddir? */
609  ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
610  ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
611  ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
612  if (engine->config->log_filename && !engine->config->use_syslog) {
613  ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
614  }
615  if (engine->config->working_dir &&
616  chdir(engine->config->working_dir) != 0) {
617  ods_log_error("[%s] chdir to %s failed: %s", engine_str,
618  engine->config->working_dir, strerror(errno));
619  return ODS_STATUS_CHDIR_ERR;
620  }
621  if (engine_privdrop(engine) != ODS_STATUS_OK) {
622  ods_log_error("[%s] unable to drop privileges", engine_str);
624  }
625 
626  /* daemonize */
627  if (engine->daemonize) {
628  switch ((engine->pid = fork())) {
629  case -1: /* error */
630  ods_log_error("[%s] unable to fork daemon: %s",
631  engine_str, strerror(errno));
632  return ODS_STATUS_FORK_ERR;
633  case 0: /* child */
634  break;
635  default: /* parent */
636  engine_cleanup(engine);
637  engine = NULL;
638  xmlCleanupParser();
639  xmlCleanupGlobals();
640  xmlCleanupThreads();
641  exit(0);
642  }
643  if (setsid() == -1) {
644  ods_log_error("[%s] unable to setsid daemon (%s)",
645  engine_str, strerror(errno));
646  return ODS_STATUS_SETSID_ERR;
647  }
648  }
649  engine->pid = getpid();
650  ods_log_verbose("[%s] running as pid %lu", engine_str,
651  (unsigned long) engine->pid);
652 
653  /* catch signals */
654  signal_set_engine(engine);
655  action.sa_handler = signal_handler;
656  sigfillset(&action.sa_mask);
657  action.sa_flags = 0;
658  sigaction(SIGHUP, &action, NULL);
659  sigaction(SIGTERM, &action, NULL);
660 
661  /* set up hsm */ /* LEAK */
662  result = lhsm_open(engine->config->cfg_filename);
663  if (result != HSM_OK) {
664  return ODS_STATUS_HSM_ERR;
665  }
666 
667  /* create workers */
668  engine_create_workers(engine);
669  engine_create_drudgers(engine);
670 
671  /* start command handler */
672  engine_start_cmdhandler(engine);
673 
674  /* write pidfile */
675  if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
676  hsm_close();
677  ods_log_error("[%s] unable to write pid file", engine_str);
679  }
680 
681  return ODS_STATUS_OK;
682 }
683 
684 
689 static int
690 engine_all_zones_processed(engine_type* engine)
691 {
692  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
693  zone_type* zone = NULL;
694 
695  ods_log_assert(engine);
696  ods_log_assert(engine->zonelist);
697  ods_log_assert(engine->zonelist->zones);
698 
699  node = ldns_rbtree_first(engine->zonelist->zones);
700  while (node && node != LDNS_RBTREE_NULL) {
701  zone = (zone_type*) node->key;
702  if (!zone->processed) {
703  return 0;
704  }
705  node = ldns_rbtree_next(node);
706  }
707  return 1;
708 }
709 
710 
715 static void
716 engine_run(engine_type* engine, int single_run)
717 {
718  if (!engine) {
719  return;
720  }
721  ods_log_assert(engine);
722 
723  engine_start_workers(engine);
724  engine_start_drudgers(engine);
725 
726  lock_basic_lock(&engine->signal_lock);
727  /* [LOCK] signal */
728  engine->signal = SIGNAL_RUN;
729  /* [UNLOCK] signal */
730  lock_basic_unlock(&engine->signal_lock);
731 
732  while (!engine->need_to_exit && !engine->need_to_reload) {
733  lock_basic_lock(&engine->signal_lock);
734  /* [LOCK] signal */
735  engine->signal = signal_capture(engine->signal);
736  switch (engine->signal) {
737  case SIGNAL_RUN:
738  ods_log_assert(1);
739  break;
740  case SIGNAL_RELOAD:
741  engine->need_to_reload = 1;
742  break;
743  case SIGNAL_SHUTDOWN:
744  engine->need_to_exit = 1;
745  break;
746  default:
747  ods_log_warning("[%s] invalid signal captured: %d, "
748  "keep running", engine_str, signal);
749  engine->signal = SIGNAL_RUN;
750  break;
751  }
752  /* [UNLOCK] signal */
753  lock_basic_unlock(&engine->signal_lock);
754 
755  if (single_run) {
756  engine->need_to_exit = engine_all_zones_processed(engine);
757  }
758 
759  lock_basic_lock(&engine->signal_lock);
760  /* [LOCK] signal */
761  if (engine->signal == SIGNAL_RUN && !single_run) {
762  ods_log_debug("[%s] taking a break", engine_str);
763  lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
764  }
765  /* [UNLOCK] signal */
766  lock_basic_unlock(&engine->signal_lock);
767  }
768  ods_log_debug("[%s] signer halted", engine_str);
769  engine_stop_drudgers(engine);
770  engine_stop_workers(engine);
771  (void)lhsm_reopen(engine->config->cfg_filename);
772  return;
773 }
774 
775 
780 static void
781 set_notify_ns(zone_type* zone, const char* cmd)
782 {
783  const char* str = NULL;
784  const char* str2 = NULL;
785 
786  ods_log_assert(cmd);
787  ods_log_assert(zone);
788  ods_log_assert(zone->name);
789  ods_log_assert(zone->adoutbound);
790 
791  if (zone->adoutbound->type == ADAPTER_FILE) {
792  str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
793  } else {
794  str = cmd;
795  }
796 
797  str2 = ods_replace(str, "%zone", zone->name);
798  free((void*)str);
799  zone->notify_ns = (const char*) str2;
800  ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
801  return;
802 }
803 
804 
809 void
811 {
812  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
813  zone_type* zone = NULL;
814  zone_type* delzone = NULL;
815  task_type* task = NULL;
816  ods_status status = ODS_STATUS_OK;
817  int wake_up = 0;
818  time_t now;
819 
820  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
821  ods_log_error("[%s] cannot update zones: no engine or zonelist",
822  engine_str);
823  return;
824  }
825  ods_log_assert(engine);
826  ods_log_assert(engine->zonelist);
827  ods_log_assert(engine->zonelist->zones);
828 
829  now = time_now();
830  reload_zonefetcher(engine);
831 
832  lock_basic_lock(&engine->zonelist->zl_lock);
833  /* [LOCK] zonelist */
834  node = ldns_rbtree_first(engine->zonelist->zones);
835  while (node && node != LDNS_RBTREE_NULL) {
836  zone = (zone_type*) node->data;
837  task = NULL; /* reset task */
838 
839  if (zone->tobe_removed) {
840  node = ldns_rbtree_next(node);
841 
842  lock_basic_lock(&zone->zone_lock);
843  /* [LOCK] zone */
844  delzone = zonelist_del_zone(engine->zonelist, zone);
845  if (delzone) {
847  /* [LOCK] schedule */
848  task = unschedule_task(engine->taskq,
849  (task_type*) zone->task);
850  /* [UNLOCK] schedule */
852  }
853  task_cleanup(task);
854  task = NULL;
855  /* [UNLOCK] zone */
857 
858  zone_cleanup(zone);
859  zone = NULL;
860  continue;
861  } else if (zone->just_added) {
862 
863  lock_basic_lock(&zone->zone_lock);
864  ods_log_assert(!zone->task);
865  zone->just_added = 0;
866  /* notify nameserver */
867  if (engine->config->notify_command && !zone->notify_ns) {
868  set_notify_ns(zone, engine->config->notify_command);
869  }
870  /* schedule task */
871  task = task_create(TASK_SIGNCONF, now, zone->name, zone);
872  if (!task) {
873  ods_log_crit("[%s] failed to create task for zone %s",
874  engine_str, zone->name);
875  } else {
876  zone->task = task;
878  /* [LOCK] schedule */
879  status = schedule_task(engine->taskq, task, 0);
880  /* [UNLOCK] schedule */
882  wake_up = 1;
883  }
884  /* zone fetcher enabled? */
885  zone->fetch = (engine->config->zonefetch_filename != NULL);
887  } else { /* always try to update signconf */
888  lock_basic_lock(&zone->zone_lock);
889  ods_log_assert(zone->task);
890  zone->just_updated = 0;
891  /* reschedule task */
893  /* [LOCK] schedule */
894  task = unschedule_task(engine->taskq, (task_type*) zone->task);
895  if (task != NULL) {
896  ods_log_debug("[%s] reschedule task for zone %s", engine_str,
897  zone->name);
898  if (task->what != TASK_SIGNCONF) {
899  task->halted = task->what;
900  task->interrupt = TASK_SIGNCONF;
901  }
902  task->what = TASK_SIGNCONF;
903  task->when = now;
904  status = schedule_task(engine->taskq, task, 0);
905  zone->task = task;
906  } else {
907  /* task not queued, being worked on? */
908  ods_log_debug("[%s] worker busy with zone %s, will update "
909  "signconf as soon as possible", engine_str, zone->name);
910  task = (task_type*) zone->task;
911  task->interrupt = TASK_SIGNCONF;
912  /* task->halted set by worker */
913  }
914  /* [UNLOCK] schedule */
917 
918  wake_up = 1;
919  }
920 
921  if (status != ODS_STATUS_OK) {
922  ods_log_crit("[%s] failed to schedule task for zone %s: %s",
923  engine_str, zone->name, ods_status2str(status));
924  task_cleanup(task);
925  zone->task = NULL;
926  }
927  node = ldns_rbtree_next(node);
928  }
929  /* [UNLOCK] zonelist */
931  if (wake_up) {
932  engine_wakeup_workers(engine);
933  }
934  return;
935 }
936 
937 
942 static ods_status
943 engine_recover(engine_type* engine)
944 {
945  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
946  zone_type* zone = NULL;
947  ods_status status = ODS_STATUS_OK;
949 
950  if (!engine || !engine->zonelist || !engine->zonelist->zones) {
951  ods_log_error("[%s] cannot update zones: no engine or zonelist",
952  engine_str);
953  return ODS_STATUS_OK; /* will trigger update zones */
954  }
955  ods_log_assert(engine);
956  ods_log_assert(engine->zonelist);
957  ods_log_assert(engine->zonelist->zones);
958 
959  lock_basic_lock(&engine->zonelist->zl_lock);
960  /* [LOCK] zonelist */
961  node = ldns_rbtree_first(engine->zonelist->zones);
962  while (node && node != LDNS_RBTREE_NULL) {
963  zone = (zone_type*) node->data;
964 
965  ods_log_assert(zone->just_added);
966  status = zone_recover(zone);
967  if (status == ODS_STATUS_OK) {
968  ods_log_assert(zone->task);
969  ods_log_assert(zone->zonedata);
970  ods_log_assert(zone->signconf);
971  /* notify nameserver */
972  if (engine->config->notify_command && !zone->notify_ns) {
973  set_notify_ns(zone, engine->config->notify_command);
974  }
975  /* zone fetcher enabled? */
976  zone->fetch = (engine->config->zonefetch_filename != NULL);
977  /* schedule task */
979  /* [LOCK] schedule */
980  status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
981  /* [UNLOCK] schedule */
983 
984  if (status != ODS_STATUS_OK) {
985  ods_log_crit("[%s] unable to schedule task for zone %s: %s",
986  engine_str, zone->name, ods_status2str(status));
987  task_cleanup((task_type*) zone->task);
988  zone->task = NULL;
989  result = ODS_STATUS_OK; /* will trigger update zones */
990  } else {
991  ods_log_verbose("[%s] recovered zone %s", engine_str,
992  zone->name);
993  /* recovery done */
994  zone->just_added = 0;
995  }
996  } else {
997  if (status != ODS_STATUS_UNCHANGED) {
998  ods_log_warning("[%s] unable to recover zone %s from backup,"
999  " performing full sign", engine_str, zone->name);
1000  }
1001  result = ODS_STATUS_OK; /* will trigger update zones */
1002  }
1003  node = ldns_rbtree_next(node);
1004  }
1005  /* [UNLOCK] zonelist */
1006  lock_basic_unlock(&engine->zonelist->zl_lock);
1007  return result;
1008 }
1009 
1010 
1015 void
1016 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
1017  int info, int single_run)
1018 {
1019  engine_type* engine = NULL;
1020  int use_syslog = 0;
1021  ods_status zl_changed = ODS_STATUS_UNCHANGED;
1022  ods_status status = ODS_STATUS_OK;
1023  int close_hsm = 0;
1024 
1025  ods_log_assert(cfgfile);
1026  ods_log_init(NULL, use_syslog, cmdline_verbosity);
1027  ods_log_verbose("[%s] starting signer", engine_str);
1028 
1029  /* initialize */
1030  xmlInitGlobals();
1031  xmlInitParser();
1032  xmlInitThreads();
1033  engine = engine_create();
1034  if (!engine) {
1035  ods_fatal_exit("[%s] create failed", engine_str);
1036  return;
1037  }
1038  engine->daemonize = daemonize;
1039 
1040  /* config */
1041  engine->config = engine_config(engine->allocator, cfgfile,
1042  cmdline_verbosity);
1043  status = engine_config_check(engine->config);
1044  if (status != ODS_STATUS_OK) {
1045  ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
1046  goto earlyexit;
1047  }
1048  if (info) {
1049  engine_config_print(stdout, engine->config); /* for debugging */
1050  goto earlyexit;
1051  }
1052 
1053  /* open log */
1054  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
1055  engine->config->verbosity);
1056 
1057  /* setup */
1058  tzset(); /* for portability */
1059  status = engine_setup(engine);
1060  if (status != ODS_STATUS_OK) {
1061  ods_log_error("[%s] setup failed: %s", engine_str,
1062  ods_status2str(status));
1063  engine->need_to_exit = 1;
1064  if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
1065  /* command handler had not yet been started */
1066  engine->cmdhandler_done = 1;
1067  }
1068  } else {
1069  /* setup ok, mark hsm open */
1070  close_hsm = 1;
1071  }
1072 
1073  /* run */
1074  while (engine->need_to_exit == 0) {
1075  /* update zone list */
1076  lock_basic_lock(&engine->zonelist->zl_lock);
1077  /* [LOCK] zonelist */
1078  zl_changed = zonelist_update(engine->zonelist,
1079  engine->config->zonelist_filename);
1080  engine->zonelist->just_removed = 0;
1081  engine->zonelist->just_added = 0;
1082  engine->zonelist->just_updated = 0;
1083  /* [UNLOCK] zonelist */
1084  lock_basic_unlock(&engine->zonelist->zl_lock);
1085 
1086  if (engine->need_to_reload) {
1087  ods_log_info("[%s] signer reloading", engine_str);
1088  engine->need_to_reload = 0;
1089  } else {
1090  ods_log_info("[%s] signer started", engine_str);
1091  zl_changed = engine_recover(engine);
1092  }
1093 
1094  /* update zones */
1095  if (zl_changed == ODS_STATUS_OK) {
1096  ods_log_debug("[%s] commit zone list changes", engine_str);
1097  engine_update_zones(engine);
1098  ods_log_debug("[%s] signer configurations updated", engine_str);
1099  zl_changed = ODS_STATUS_UNCHANGED;
1100  }
1101 
1102  engine_run(engine, single_run);
1103  }
1104 
1105  /* shutdown */
1106  ods_log_info("[%s] signer shutdown", engine_str);
1107  stop_zonefetcher(engine);
1108  if (close_hsm) {
1109  hsm_close();
1110  }
1111  if (engine->cmdhandler != NULL) {
1112  engine_stop_cmdhandler(engine);
1113  }
1114 
1115 earlyexit:
1116  if (engine && engine->config) {
1117  if (engine->config->pid_filename) {
1118  (void)unlink(engine->config->pid_filename);
1119  }
1120  if (engine->config->clisock_filename) {
1121  (void)unlink(engine->config->clisock_filename);
1122  }
1123  }
1124  engine_cleanup(engine);
1125  engine = NULL;
1126  ods_log_close();
1127  xmlCleanupParser();
1128  xmlCleanupGlobals();
1129  xmlCleanupThreads();
1130  return;
1131 }
1132 
1133 
1138 void
1140 {
1141  size_t i = 0;
1142  allocator_type* allocator;
1143  cond_basic_type signal_cond;
1144  lock_basic_type signal_lock;
1145 
1146  if (!engine) {
1147  return;
1148  }
1149  allocator = engine->allocator;
1150  signal_cond = engine->signal_cond;
1151  signal_lock = engine->signal_lock;
1152 
1153  if (engine->workers && engine->config) {
1154  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
1155  worker_cleanup(engine->workers[i]);
1156  }
1157  allocator_deallocate(allocator, (void*) engine->workers);
1158  }
1159  if (engine->drudgers && engine->config) {
1160  for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
1161  worker_cleanup(engine->drudgers[i]);
1162  }
1163  allocator_deallocate(allocator, (void*) engine->drudgers);
1164  }
1165  zonelist_cleanup(engine->zonelist);
1166  schedule_cleanup(engine->taskq);
1167  fifoq_cleanup(engine->signq);
1168  cmdhandler_cleanup(engine->cmdhandler);
1169  engine_config_cleanup(engine->config);
1170  allocator_deallocate(allocator, (void*) engine);
1171 
1172  lock_basic_destroy(&signal_lock);
1173  lock_basic_off(&signal_cond);
1174  allocator_cleanup(allocator);
1175  return;
1176 }