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