OpenDNSSEC-enforcer  2.0.2
keystate_list_cmd.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 "daemon/cmdhandler.h"
33 #include "daemon/engine.h"
34 #include "file.h"
35 #include "log.h"
36 #include "str.h"
37 #include "clientpipe.h"
38 
39 #include "db/key_state.h"
40 #include "db/hsm_key.h"
41 #include "db/zone.h"
42 
44 
45 static const char *module_str = "keystate_list_task";
46 
47 /* shorter defines to keep keystate table more readable */
48 #define HID KEY_STATE_STATE_HIDDEN
49 #define RUM KEY_STATE_STATE_RUMOURED
50 #define OMN KEY_STATE_STATE_OMNIPRESENT
51 #define UNR KEY_STATE_STATE_UNRETENTIVE
52 #define NAV KEY_STATE_STATE_NA
53 
55 const char* statenames[] = {"generate", "publish", "ready",
56  "active", "retire", "dead", "unknown", "mixed"};
57 
64 static int
65 keystate(int p, int c, int introducing, key_data_ds_at_parent_t dsstate)
66 {
67  int dsseen = (dsstate == KEY_DATA_DS_AT_PARENT_SEEN);
68  int dsretract = (dsstate == KEY_DATA_DS_AT_PARENT_RETRACT);
69 
70  if (introducing) {
71  if (p == HID && c == HID) return KS_GEN;
72  if (p == HID || c == HID) return KS_PUB;
73  if (p == OMN && c == OMN) return KS_ACT;
74  if (p == RUM && dsseen && c == OMN) return KS_ACT;
75  if (p == RUM || c == RUM) return KS_RDY;
76  return KS_UNK;
77  } else {
78  /* retire conforms better to 1.4 terminology than dead. */
79  if (p == HID && c == HID) return KS_RET; /* dead */
80  if (p == UNR || c == UNR) return KS_RET;
81  if (p == RUM && dsseen && c == OMN) return KS_ACT;
82  if (p == OMN && c == OMN) return KS_ACT;
83  return KS_RET;
84  }
85 }
86 
87 static int
88 zskstate(key_data_t *key)
89 {
90  return keystate(key_state_state(key_data_cached_dnskey(key)),
93 }
94 
95 static int
96 kskstate(key_data_t *key)
97 {
98  return keystate(key_state_state(key_data_cached_ds(key)),
101  key_data_ds_at_parent(key));
102 }
103 
108 const char*
110 {
111  int z,k;
112  switch(key_data_role(key)) {
113  case KEY_DATA_ROLE_KSK:
114  return statenames[kskstate(key)];
115  case KEY_DATA_ROLE_ZSK:
116  return statenames[zskstate(key)];
117  case KEY_DATA_ROLE_CSK:
118  k = kskstate(key);
119  z = zskstate(key);
120  if (k != z) return statenames[KS_MIX];
121  return statenames[k];
122  default:
123  return statenames[KS_UNK];
124  }
125 }
126 
131 static char*
132 map_keytime(const zone_t *zone, const key_data_t *key)
133 {
134  char ct[26];
135  struct tm srtm;
136  time_t t;
137 
138  switch(key_data_ds_at_parent(key)) {
140  return strdup("waiting for ds-submit");
142  return strdup("waiting for ds-seen");
144  return strdup("waiting for ds-retract");
146  return strdup("waiting for ds-gone");
147  default:
148  break;
149  }
150  if (zone_next_change(zone) < 0)
151  return strdup("-");
152 
153  t = (time_t)zone_next_change(zone);
154  localtime_r(&t, &srtm);
155  strftime(ct, 26, "%Y-%m-%d %H:%M:%S", &srtm);
156  return strdup(ct);
157 }
158 
159 static int
160 perform_keystate_list(int sockfd, db_connection_t *dbconn,
161  const char* filterZone, char** filterKeytype, char** filterKeystate,
162  void (printheader)(int sockfd),
163  void (printkey)(int sockfd, zone_t* zone, key_data_t* key, char*tchange, hsm_key_t* hsmKey)) {
164  key_data_list_t* key_list;
165  key_data_t* key;
166  zone_t *zone = NULL;
167  char* tchange;
168  hsm_key_t *hsmkey;
169  int cmp;
170  int i, skipPrintKey;
171 
172  if (!(key_list = key_data_list_new_get(dbconn))) {
173  client_printf_err(sockfd, "Unable to get list of keys, memory "
174  "allocation or database error!\n");
175  return 1;
176  }
177 
178  if (printheader) {
179  (*printheader)(sockfd);
180  }
181 
182  while ((key = key_data_list_get_next(key_list))) {
183  /* only refetches zone if different from previous */
184  if (zone
185  && (db_value_cmp(zone_id(zone), key_data_zone_id(key), &cmp)
186  || cmp)) {
187  zone_free(zone);
188  zone = NULL;
189  }
190  if (!zone) {
191  zone = key_data_get_zone(key);
192  }
193  hsmkey = key_data_get_hsm_key(key);
195  tchange = map_keytime(zone, key); /* allocs */
196  skipPrintKey = 0;
197  if(printkey == NULL)
198  skipPrintKey = 1;
199  if(filterZone != NULL && strcmp(zone_name(zone), filterZone))
200  skipPrintKey = 1;
201  for(i=0; filterKeytype && filterKeytype[i]; i++)
202  if(!strcasecmp(filterKeytype[i],key_data_role_text(key)))
203  break;
204  if(filterKeytype && filterKeytype[i] == NULL)
205  skipPrintKey = 1;
206  for(i=0; filterKeystate && filterKeystate[i]; i++)
207  if(!strcasecmp(filterKeystate[i],map_keystate(key)))
208  break;
209  if(filterKeystate && filterKeystate[i] == NULL)
210  skipPrintKey = 1;
211  if (!skipPrintKey) {
212  (*printkey)(sockfd, zone, key, tchange, hsmkey);
213  }
214  free(tchange);
215  hsm_key_free(hsmkey);
216  key_data_free(key);
217  }
218  zone_free(zone);
219  key_data_list_free(key_list);
220  return 0;
221 }
222 
223 static void
224 usage(int sockfd)
225 {
226  client_printf(sockfd,
227  "key list\n"
228  " [--verbose] aka -v\n"
229  " [--debug] aka -d\n"
230  " [--parsable] aka -p\n"
231  " [--zone] aka -z \n"
232  " [--keystate | --all] aka -k | -a \n"
233  );
234 }
235 
236 static void
237 help(int sockfd)
238 {
239  client_printf(sockfd,
240  "List the keys in the enforcer database.\n"
241  "\nOptions:\n"
242  "verbose also show additional key parameters\n"
243  "debug print information about the keystate\n"
244  "parsable output machine parsable list\n"
245  "zone limit the output to the specific zone\n"
246  "keytype limit the output to the given type, can be ZSK, KSK, or CSK\n"
247  "keystate limit the output to the given state\n"
248  "all print keys in all states (including generate) \n\n");
249 }
250 
251 static int
252 handles(const char *cmd, ssize_t n)
253 {
254  return ods_check_command(cmd, n, key_list_funcblock()->cmdname)?1:0;
255 }
256 
257 static void
258 printcompatheader(int sockfd) {
259  client_printf(sockfd, "Keys:\n");
260  client_printf(sockfd, "%-31s %-8s %-9s %s\n", "Zone:", "Keytype:", "State:",
261  "Date of next transition:");
262 }
263 
264 static void
265 printcompatkey(int sockfd, zone_t* zone, key_data_t* key, char*tchange, hsm_key_t* hsmkey) {
266  (void)hsmkey;
267  client_printf(sockfd,
268  "%-31s %-8s %-9s %s\n",
269  zone_name(zone),
270  key_data_role_text(key),
271  map_keystate(key),
272  tchange);
273 }
274 
275 static void
276 printverboseheader(int sockfd) {
277  client_printf(sockfd, "Keys:\n");
278  client_printf(sockfd, "%-31s %-8s %-9s %-24s %-5s %-10s %-32s %-11s %s\n", "Zone:", "Keytype:", "State:",
279  "Date of next transition:", "Size:", "Algorithm:", "CKA_ID:",
280  "Repository:", "KeyTag:");
281 }
282 
283 static void
284 printverbosekey(int sockfd, zone_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
285  (void)tchange;
286  client_printf(sockfd,
287  "%-31s %-8s %-9s %-24s %-5d %-10d %-32s %-11s %d\n",
288  zone_name(zone),
289  key_data_role_text(key),
290  map_keystate(key),
291  tchange,
292  hsm_key_bits(hsmkey),
293  hsm_key_algorithm(hsmkey),
294  hsm_key_locator(hsmkey),
295  hsm_key_repository(hsmkey),
296  key_data_keytag(key));
297 }
298 
299 static void
300 printverboseparsablekey(int sockfd, zone_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
301  client_printf(sockfd,
302  "%s;%s;%s;%s;%d;%d;%s;%s;%d\n",
303  zone_name(zone),
304  key_data_role_text(key),
305  map_keystate(key),
306  tchange,
307  hsm_key_bits(hsmkey),
308  hsm_key_algorithm(hsmkey),
309  hsm_key_locator(hsmkey),
310  hsm_key_repository(hsmkey),
311  key_data_keytag(key));
312 }
313 
314 static void
315 printdebugheader(int sockfd) {
316  client_printf(sockfd,
317  "Keys:\nZone: Key role: "
318  "DS: DNSKEY: RRSIGDNSKEY: RRSIG: "
319  "Pub: Act: Id:\n");
320 }
321 
322 static void
323 printdebugkey(int sockfd, zone_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
324  (void)tchange;
325  client_printf(sockfd,
326  "%-31s %-13s %-12s %-12s %-12s %-12s %d %4d %s\n",
327  zone_name(zone),
328  key_data_role_text(key),
333  key_data_publish(key),
335  hsm_key_locator(hsmkey));
336 }
337 
338 static void
339 printdebugparsablekey(int sockfd, zone_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
340  (void)tchange;
341  client_printf(sockfd,
342  "%s;%s;%s;%s;%s;%s;%d;%d;%s\n",
343  zone_name(zone),
344  key_data_role_text(key),
349  key_data_publish(key),
351  hsm_key_locator(hsmkey));
352 }
353 
354 static char **
355 tokenizeparam(char *argument)
356 {
357  char** tokenized;
358  char** newtokenized;
359  int argCount;
360  char* argString;
361  char* argSavePtr = NULL;
362  int argSize = 8;
363 
364  if ((argString = strtok_r(argument, ",", &argSavePtr)) != NULL) {
365  if ((tokenized = malloc(sizeof (char*)*argSize)) == NULL) {
366  return NULL;
367  }
368  argCount = 0;
369  do {
370  if (strcmp(argString, "")) {
371  tokenized[argCount] = argString;
372  ++argCount;
373  if (argCount == argSize) {
374  argSize *= 2;
375  if ((newtokenized = realloc(tokenized, sizeof (char*)*argSize)) == NULL) {
376  free(tokenized);
377  return NULL;
378  }
379  tokenized = newtokenized;
380  }
381  }
382  } while (strtok_r(NULL, ",", &argSavePtr) != NULL);
383  tokenized[argCount] = NULL;
384  } else {
385  if ((tokenized = malloc(sizeof (char*)*2)) == NULL) {
386  return NULL;
387  }
388  tokenized[0] = argument;
389  tokenized[1] = NULL;
390  }
391  return tokenized;
392 }
393 
394 static int
395 run(int sockfd, engine_type* engine, const char *cmd, ssize_t n,
396  db_connection_t *dbconn) {
397  char buf[ODS_SE_MAXLINE];
398 #define NARGV 12
399  const char *argv[NARGV];
400  int success, argIndex;
401  int argc, bVerbose, bDebug, bParsable, bAll;
402  char* keytypeParam;
403  char* keystateParam;
404  const char* filterZone; /* NULL if no filtering on zone, otherwise zone to match */
405  char** filterKeytype; /* NULL if no filtering on key type, NULL terminated list of key types to filter */
406  char** filterKeystate; /* NULL if no filtering on key state, NULL terminated list of key states to filter */
407  (void) engine;
408 
409  ods_log_debug("[%s] %s command", module_str, key_list_funcblock()->cmdname);
410 
411  cmd = ods_check_command(cmd, n, key_list_funcblock()->cmdname);
412  /* Use buf as an intermediate buffer for the command. */
413  strncpy(buf, cmd, sizeof (buf));
414  buf[sizeof (buf) - 1] = '\0';
415 
416  /* separate the arguments */
417  argc = ods_str_explode(buf, NARGV, argv);
418  if (argc > NARGV) {
419  ods_log_warning("[%s] too many arguments for %s command",
420  module_str, key_list_funcblock()->cmdname);
421  client_printf(sockfd, "too many arguments\n");
422  return -1;
423  }
424 
425  bVerbose = ods_find_arg(&argc, argv, "verbose", "v") != -1;
426  bDebug = ods_find_arg(&argc, argv, "debug", "d") != -1;
427  bParsable = ods_find_arg(&argc, argv, "parsable", "p") != -1;
428  if ((argIndex = ods_find_arg_and_param(&argc, argv, "zone", "z", &filterZone)) == -1) {
429  filterZone = NULL;
430  }
431  if (ods_find_arg_and_param(&argc, argv, "keytype", "k", (const char **)&keytypeParam) == -1) {
432  keytypeParam = NULL;
433  }
434  if (ods_find_arg_and_param(&argc, argv, "keystate", "e", (const char **)&keystateParam) == -1) {
435  keystateParam = NULL;
436  }
437 
438  bAll = (ods_find_arg(&argc, argv, "all", "a") != -1);
439 
440  if (keystateParam != NULL && bAll) {
441  client_printf(sockfd, "Error: --keystate and --all option cannot be given together\n");
442  return -1;
443  }
444 
445  if (argc) {
446  ods_log_warning("[%s] unknown arguments for %s command", module_str, key_list_funcblock()->cmdname);
447  client_printf(sockfd, "unknown arguments\n");
448  return -1;
449  }
450 
451  if (keytypeParam)
452  filterKeytype = tokenizeparam(keytypeParam);
453  else
454  filterKeytype = NULL;
455  if (keystateParam) {
456  filterKeystate = tokenizeparam(keystateParam);
457  } else
458  filterKeystate = NULL;
459  if (bAll) {
460  if (filterKeystate != NULL) {
461  free(filterKeystate);
462  }
463  filterKeystate = NULL;
464  } else if(filterKeystate == NULL) {
465  if ((filterKeystate = malloc(sizeof (char*) * 6))) {
466  filterKeystate[0] = (char *)"publish";
467  filterKeystate[1] = (char *)"ready";
468  filterKeystate[2] = (char *)"active";
469  filterKeystate[3] = (char *)"retire";
470  filterKeystate[4] = (char *)"mixed";
471  filterKeystate[5] = NULL;
472  } /* else emit error */
473  }
474 
475  if (bDebug) {
476  if (bParsable) {
477  success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, NULL, &printdebugparsablekey);
478  } else {
479  success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printdebugheader, &printdebugkey);
480  }
481  } else if (bVerbose) {
482  if (bParsable) {
483  success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, NULL, &printverboseparsablekey);
484  } else {
485  success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printverboseheader, &printverbosekey);
486  }
487  } else {
488  success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printcompatheader, &printcompatkey);
489  }
490 
491  if (filterKeytype)
492  free(filterKeytype);
493  if (filterKeystate)
494  free(filterKeystate);
495  return success;
496 }
497 
498 static struct cmd_func_block funcblock = {
499  "key list", &usage, &help, &handles, &run
500 };
501 
502 struct cmd_func_block*
504 {
505  return &funcblock;
506 }
const char * key_data_role_text(const key_data_t *key_data)
Definition: key_data.c:711
const char * key_state_state_text(const key_state_t *key_state)
Definition: key_state.c:377
key_data_role
Definition: key_data.h:40
void(* help)(int sockfd)
Definition: cmdhandler.h:64
hsm_key_t * key_data_get_hsm_key(const key_data_t *key_data)
Definition: key_data.c:649
void ods_log_debug(const char *format,...)
Definition: log.c:41
unsigned int key_data_publish(const key_data_t *key_data)
Definition: key_data.c:743
unsigned int key_data_active_zsk(const key_data_t *key_data)
Definition: key_data.c:735
key_data_list_t * key_data_list_new_get(const db_connection_t *connection)
Definition: key_data.c:2102
const db_value_t * key_data_zone_id(const key_data_t *key_data)
Definition: key_data.c:561
int(* run)(int sockfd, struct engine_struct *engine, const char *cmd, ssize_t n, db_connection_t *dbconn)
Definition: cmdhandler.h:79
int zone_next_change(const zone_t *zone)
Definition: zone.c:806
struct cmd_func_block * key_list_funcblock(void)
enum key_data_ds_at_parent key_data_ds_at_parent_t
unsigned int key_data_keytag(const key_data_t *key_data)
Definition: key_data.c:767
key_data_t * key_data_list_get_next(key_data_list_t *key_data_list)
Definition: key_data.c:2425
const char * hsm_key_repository(const hsm_key_t *hsm_key)
Definition: hsm_key.c:568
void zone_free(zone_t *zone)
Definition: zone.c:325
#define OMN
unsigned int key_data_introducing(const key_data_t *key_data)
Definition: key_data.c:727
void(* usage)(int sockfd)
Definition: cmdhandler.h:61
const key_state_t * key_data_cached_rrsigdnskey(key_data_t *key_data)
Definition: key_data_ext.c:72
int db_value_cmp(const db_value_t *value_a, const db_value_t *value_b, int *result)
Definition: db_value.c:102
const char * statenames[]
key_data_ds_at_parent
Definition: key_data.h:48
int key_data_cache_key_states(key_data_t *key_data)
Definition: key_data_ext.c:33
#define UNR
const char * hsm_key_locator(const hsm_key_t *hsm_key)
Definition: hsm_key.c:520
zone_t * key_data_get_zone(const key_data_t *key_data)
Definition: key_data.c:569
key_state_state
Definition: key_state.h:49
const char * zone_name(const zone_t *zone)
Definition: zone.c:782
const char * map_keystate(key_data_t *key)
#define NARGV
const key_state_t * key_data_cached_rrsig(key_data_t *key_data)
Definition: key_data_ext.c:64
const key_state_t * key_data_cached_ds(key_data_t *key_data)
Definition: key_data_ext.c:60
void key_data_list_free(key_data_list_t *key_data_list)
Definition: key_data.c:1694
const key_state_t * key_data_cached_dnskey(key_data_t *key_data)
Definition: key_data_ext.c:68
void key_data_free(key_data_t *key_data)
Definition: key_data.c:304
const db_value_t * zone_id(const zone_t *zone)
Definition: zone.c:728
unsigned int hsm_key_algorithm(const hsm_key_t *hsm_key)
Definition: hsm_key.c:544
void hsm_key_free(hsm_key_t *hsm_key)
Definition: hsm_key.c:286
unsigned int key_data_active_ksk(const key_data_t *key_data)
Definition: key_data.c:751
Definition: zone.h:46
int(* handles)(const char *cmd, ssize_t n)
Definition: cmdhandler.h:67
#define HID
unsigned int hsm_key_bits(const hsm_key_t *hsm_key)
Definition: hsm_key.c:536
#define RUM
void ods_log_warning(const char *format,...)
Definition: log.c:62