OpenDNSSEC-enforcer  2.0.4
enforce_task.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Surfnet
3  * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation).
4  * Copyright (c) 2011 OpenDNSSEC AB (svb)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include "config.h"
31 
32 #include <pthread.h>
33 
34 #include "enforcer/enforcer.h"
35 #include "clientpipe.h"
36 #include "daemon/engine.h"
37 #include "signconf/signconf_task.h"
40 #include "duration.h"
41 #include "file.h"
42 #include "log.h"
43 #include "scheduler/schedule.h"
44 #include "scheduler/task.h"
45 #include "db/zone.h"
46 #include "db/db_clause.h"
47 
48 #include "enforcer/enforce_task.h"
49 
50 static const char *module_str = "enforce_task";
51 
52 static void
53 enf_schedule_task(int sockfd, engine_type* engine, task_type *task, const char *what)
54 {
55  /* schedule task */
56  if (!task) {
57  ods_log_crit("[%s] failed to create %s task", module_str, what);
58  } else {
59  ods_status status = schedule_task(engine->taskq, task);
60  if (status != ODS_STATUS_OK) {
61  ods_log_crit("[%s] failed to create %s task", module_str, what);
62  client_printf(sockfd, "Unable to schedule %s task.\n", what);
63  } else {
64  client_printf(sockfd, "Scheduled %s task.\n", what);
65  }
66  }
67 }
68 
69 static void
70 reschedule_enforce(task_type *task, time_t t_when, const char *z_when)
71 {
72  ods_log_assert(task->who);
73  free(task->who);
74  task->who = strdup(z_when);
75  task->when = t_when;
76  task->backoff = 0;
77 }
78 
79 static time_t
80 perform_enforce(int sockfd, engine_type *engine, int bForceUpdate,
81  task_type* task, db_connection_t *dbconn)
82 {
83  zone_list_t *zonelist = NULL;
84  zone_t *zone, *firstzone = NULL;
86  key_data_list_t *keylist;
87  const key_data_t *key;
88  time_t t_next, t_now = time_now(), t_reschedule = -1;
89  /* Flags that indicate tasks to be scheduled after zones have been
90  * enforced. */
91  int bSignerConfNeedsWriting = 0;
92  int bSubmitToParent = 0;
93  int bRetractFromParent = 0;
94  int zone_updated;
95 
96  if (!(zonelist = zone_list_new(dbconn))
97  /*|| zone_list_associated_fetch(zonelist)*/
98  || zone_list_get(zonelist))
99  {
100  zone_list_free(zonelist);
101  zonelist = NULL;
102  }
103  if (!zonelist) {
104  /* TODO: log error */
105  ods_log_error("[%s] zonelist NULL", module_str);
106  /* TODO: backoff? */
107  return t_reschedule;
108  }
109 
110  for (zone = zone_list_get_next(zonelist); zone;
111  zone_free(zone), zone = zone_list_get_next(zonelist))
112  {
113  if (engine->need_to_reload || engine->need_to_exit) break;
114 
115  if (!bForceUpdate && (zone_next_change(zone) == -1)) {
116  continue;
117  } else if (zone_next_change(zone) > t_now && !bForceUpdate) {
118  /* This zone needs no update, however it might be the first
119  * for future updates */
120  if (zone_next_change(zone) < t_reschedule || !firstzone)
121  {
122  t_reschedule = zone_next_change(zone);
123  if (firstzone) {
124  zone_free(firstzone);
125  }
126  firstzone = zone;
127  zone = NULL; /* keeps firstzone from being freed. */
128  }
129  continue;
130  }
131  if (!(policy = zone_get_policy(zone))) {
132  client_printf(sockfd,
133  "Next update for zone %s NOT scheduled "
134  "because policy is missing !\n", zone_name(zone));
135  if (zone_next_change(zone) != -1
136  && (zone_set_next_change(zone, -1)
137  || zone_update(zone)))
138  {
139  /* TODO: Log error */
140  }
141  continue;
142  }
143 
144  if (policy_passthrough(policy)) {
145  ods_log_info("Passing through zone %s.\n", zone_name(zone));
147  zone_update(zone);
148  bSignerConfNeedsWriting = 1;
149  policy_free(policy);
150  continue;
151  }
152 
153  zone_updated = 0;
154  t_next = update(engine, dbconn, zone, policy, t_now, &zone_updated);
155  policy_free(policy);
156  bSignerConfNeedsWriting |= zone_signconf_needs_writing(zone);
157 
158  keylist = zone_get_keys(zone);
159  while ((key = key_data_list_next(keylist))) {
161  ods_log_warning("[%s] please submit DS "
162  "with keytag %d for zone %s",
163  module_str, key_data_keytag(key)&0xFFFF, zone_name(zone));
164  bSubmitToParent = 1;
166  ods_log_warning("[%s] please retract DS "
167  "with keytag %d for zone %s",
168  module_str, key_data_keytag(key)&0xFFFF, zone_name(zone));
169  bRetractFromParent = 1;
170  }
171  }
172  key_data_list_free(keylist);
173 
174  if (t_next == -1) {
175  client_printf(sockfd,
176  "Next update for zone %s NOT scheduled "
177  "by enforcer !\n", zone_name(zone));
178  ods_log_debug("Next update for zone %s NOT scheduled "
179  "by enforcer !\n", zone_name(zone));
180  } else {
181  /* Invalid schedule time then skip the zone.*/
182  char tbuf[32] = "date/time invalid\n"; /* at least 26 bytes */
183  ctime_r(&t_next, tbuf); /* note that ctime_r inserts \n */
184  client_printf(sockfd,
185  "Next update for zone %s scheduled at %s",
186  zone_name(zone), tbuf);
187  ods_log_debug("Next update for zone %s scheduled at %s",
188  zone_name(zone), tbuf);
189  }
190  if (zone_next_change(zone) != t_next) {
191  zone_set_next_change(zone, t_next);
192  zone_updated = 1;
193  }
194 
195  /*
196  * Commit the changes to the zone if there where any.
197  */
198  if (zone_updated) {
199  if (zone_update(zone)) {
200  ods_log_debug("[%s] error zone_update(%s)", module_str, zone_name(zone));
201  }
202  }
203 
204  /*
205  * Find out when to schedule the next change.
206  */
207  if (zone_next_change(zone) != -1
208  && (zone_next_change(zone) < t_reschedule
209  || !firstzone))
210  {
211  t_reschedule = zone_next_change(zone);
212  if (firstzone) {
213  zone_free(firstzone);
214  }
215  firstzone = zone;
216  zone = NULL;
217  }
218  }
219  zone_list_free(zonelist);
220 
221  /*
222  * Schedule the next change if needed.
223  */
224  if (firstzone) {
225  reschedule_enforce(task, t_reschedule, zone_name(firstzone));
226  zone_free(firstzone);
227  }
228 
229  /* Launch signer configuration writer task when one of the
230  * zones indicated that it needs to be written.
231  * TODO: unschedule it first!
232  */
233  if (bSignerConfNeedsWriting) {
234  task_type *signconf =
235  signconf_task(dbconn, "signconf", "signer configurations");
236  enf_schedule_task(sockfd,engine,signconf,"signconf");
237  } else {
238  ods_log_info("[%s] No changes to any signconf file required", module_str);
239  }
240 
241  /* Launch ds-submit task when one of the updated key states has the
242  * DS_SUBMIT flag set. */
243  if (bSubmitToParent) {
244  task_type *submit =
245  keystate_ds_submit_task(engine);
246  enf_schedule_task(sockfd, engine, submit, "ds-submit");
247  }
248 
249 
250  /* Launch ds-retract task when one of the updated key states has the
251  * DS_RETRACT flag set. */
252  if (bRetractFromParent) {
253  task_type *retract =
254  keystate_ds_retract_task(engine);
255  enf_schedule_task(sockfd, engine, retract, "ds-retract");
256  }
257 
258 
259  return t_reschedule;
260 }
261 
262 time_t perform_enforce_lock(int sockfd, engine_type *engine,
263  int bForceUpdate, task_type* task, db_connection_t *dbconn)
264 {
265  time_t returntime;
266  if (pthread_mutex_trylock(&engine->enforce_lock)) {
267  client_printf(sockfd, "An other enforce task is already running."
268  " No action taken.\n");
269  return 0;
270  }
271  returntime = perform_enforce(sockfd, engine, bForceUpdate, task,
272  dbconn);
273  pthread_mutex_unlock(&engine->enforce_lock);
274  return returntime;
275 }
276 
277 struct enf_task_ctx {
280 };
281 
282 static struct enf_task_ctx enforcer_context;
283 
284 static task_type*
285 enforce_task_clean_ctx(task_type *task)
286 {
287  task->context = NULL;
288  return NULL;
289 }
290 
291 static task_type *
292 enforce_task_perform(task_type *task)
293 {
294  engine_type *engine = ((struct enf_task_ctx *)task->context)->engine;
295  int enforce_all = ((struct enf_task_ctx *)task->context)->enforce_all;
296  int return_time = perform_enforce_lock(-1, engine, enforce_all,
297  task, task->dbconn);
298  enforcer_context.enforce_all = 0;
299  if (return_time != -1) return task;
300  task_cleanup(task);
301  return NULL;
302 }
303 
304 task_type *
305 enforce_task(engine_type *engine, bool all)
306 {
307  task_id what_id;
308  const char *what = "enforce";
309  const char *who = "next zone";
310  struct enf_task_ctx *ctx = &enforcer_context;
311  if (!ctx) {
312  ods_log_error("Malloc failure, enforce task not scheduled");
313  return NULL;
314  }
315  ctx->engine = engine;
316  ctx->enforce_all = all;
317  what_id = task_register(what, module_str, enforce_task_perform);
318  return task_create(what_id, time_now(), who, what, ctx,
319  enforce_task_clean_ctx);
320 }
321 
322 int
323 flush_enforce_task(engine_type *engine, bool enforce_all)
324 {
325  int status;
326  task_id what_id;
327 
328  /* flush (force to run) the enforcer task when it is waiting in the
329  task list. */
330  if (!task_id_from_long_name(module_str, &what_id)) {
331  /* no such task */
332  return 1;
333  }
334 
335  enforcer_context.enforce_all = enforce_all;
336 
337  if (!schedule_flush_type(engine->taskq, what_id)) {
338  status = schedule_task(engine->taskq, enforce_task(engine, enforce_all));
339  if (status != ODS_STATUS_OK) {
340  ods_fatal_exit("[%s] failed to create enforce task", module_str);
341  return 0;
342  }
343  }
344  return 1;
345 }
void ods_log_debug(const char *format,...)
Definition: log.c:41
time_t when
Definition: task.h:63
task_type * keystate_ds_submit_task(engine_type *engine)
char * who
Definition: task.h:66
int zone_update(zone_t *zone)
Definition: zone.c:1589
policy_t * zone_get_policy(const zone_t *zone)
Definition: zone.c:744
void ods_fatal_exit(const char *format,...)
Definition: log.c:94
time_t perform_enforce_lock(int sockfd, engine_type *engine, int bForceUpdate, task_type *task, db_connection_t *dbconn)
Definition: enforce_task.c:262
void zone_list_free(zone_list_t *zone_list)
Definition: zone.c:1989
void ods_log_info(const char *format,...)
Definition: log.c:55
time_t backoff
Definition: task.h:64
int zone_next_change(const zone_t *zone)
Definition: zone.c:806
key_data_list_t * zone_get_keys(const zone_t *zone)
Definition: zone_ext.c:38
void * context
Definition: task.h:68
ods_status schedule_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:401
int zone_set_signconf_needs_writing(zone_t *zone, unsigned int signconf_needs_writing)
Definition: zone.c:959
void ods_log_error(const char *format,...)
Definition: log.c:69
bool task_id_from_long_name(const char *long_name, task_id *pwhat)
Definition: task.c:53
unsigned int key_data_keytag(const key_data_t *key_data)
Definition: key_data.c:767
unsigned int policy_passthrough(const policy_t *policy)
Definition: policy.c:1085
time_t update(engine_type *engine, db_connection_t *dbconn, zone_t *zone, policy_t *policy, time_t now, int *zone_updated)
Definition: enforcer.c:2719
enum task_id_enum task_id
Definition: task.h:53
void zone_free(zone_t *zone)
Definition: zone.c:325
void ods_log_crit(const char *format,...)
Definition: log.c:80
task_type * enforce_task(engine_type *engine, bool all)
Definition: enforce_task.c:305
zone_list_t * zone_list_new(const db_connection_t *connection)
Definition: zone.c:1946
void policy_free(policy_t *policy)
Definition: policy.c:518
int zone_set_next_change(zone_t *zone, int next_change)
Definition: zone.c:991
key_data_ds_at_parent
Definition: key_data.h:48
unsigned int zone_signconf_needs_writing(const zone_t *zone)
Definition: zone.c:790
const key_data_t * key_data_list_next(key_data_list_t *key_data_list)
Definition: key_data.c:2359
void task_cleanup(task_type *task)
Definition: task.c:147
db_connection_t * dbconn
Definition: task.h:71
task_type * signconf_task(const db_connection_t *dbconn, const char *what, const char *who)
Definition: signconf_task.c:73
const char * zone_name(const zone_t *zone)
Definition: zone.c:782
zone_t * zone_list_get_next(zone_list_t *zone_list)
Definition: zone.c:2666
pthread_mutex_t enforce_lock
Definition: engine.h:72
int schedule_flush_type(schedule_type *schedule, task_id id)
Definition: schedule.c:298
void key_data_list_free(key_data_list_t *key_data_list)
Definition: key_data.c:1694
task_type * keystate_ds_retract_task(engine_type *engine)
int zone_list_get(zone_list_t *zone_list)
Definition: zone.c:2360
schedule_type * taskq
Definition: engine.h:55
task_id task_register(const char *short_name, const char *long_name, how_type how)
Definition: task.c:82
task_type * task_create(task_id what_id, time_t when, const char *who, const char *what, void *context, how_type clean_context)
Definition: task.c:110
Definition: policy.h:60
engine_type * engine
Definition: enforce_task.c:278
Definition: zone.h:46
int need_to_exit
Definition: engine.h:65
int need_to_reload
Definition: engine.h:66
void ods_log_warning(const char *format,...)
Definition: log.c:62
int flush_enforce_task(engine_type *engine, bool enforce_all)
Definition: enforce_task.c:323