OpenDNSSEC-enforcer  2.1.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 <getopt.h>
31 #include "config.h"
32 
33 #include "cmdhandler.h"
35 #include "daemon/engine.h"
36 #include "file.h"
37 #include "duration.h"
38 #include "log.h"
39 #include "str.h"
40 #include "clientpipe.h"
41 
42 #include "db/key_state.h"
43 #include "db/hsm_key.h"
44 #include "db/zone_db.h"
45 
47 
48 static const char *module_str = "keystate_list_task";
49 
50 /* shorter defines to keep keystate table more readable */
51 #define HID KEY_STATE_STATE_HIDDEN
52 #define RUM KEY_STATE_STATE_RUMOURED
53 #define OMN KEY_STATE_STATE_OMNIPRESENT
54 #define UNR KEY_STATE_STATE_UNRETENTIVE
55 #define NAV KEY_STATE_STATE_NA
56 
58 const char* statenames[] = {"generate", "publish", "ready",
59  "active", "retire", "unknown", "mixed"};
60 
67 static int
68 keystate(int p, int c, int introducing, key_data_ds_at_parent_t dsstate)
69 {
70  int dsseen = (dsstate == KEY_DATA_DS_AT_PARENT_SEEN);
71  int dsretract = (dsstate == KEY_DATA_DS_AT_PARENT_RETRACT);
72 
73  if (p == OMN && c == OMN) return KS_ACT;
74  if (p == RUM && dsseen && c == OMN) return KS_ACT;
75  if (introducing) {
76  if (p == HID && c == HID) return KS_GEN;
77  if (p == HID || c == HID) return KS_PUB;
78  if (p == OMN || c == OMN) return KS_RDY;
79  if (p == RUM || c == RUM) return KS_RDY;
80  return KS_UNK;
81  } else {
82  /* retire conforms better to 1.4 terminology than dead. */
83  if (p == HID && c == HID) return KS_RET; /* dead */
84  if (p == UNR || c == UNR) return KS_RET;
85  if (p == OMN || c == OMN) return KS_RDY;
86  if (p == RUM || c == RUM) return KS_RDY;
87  return KS_RET;
88  }
89 }
90 
91 static int
92 zskstate(key_data_t *key)
93 {
94  return keystate(key_state_state(key_data_cached_dnskey(key)),
97 }
98 
99 static int
100 kskstate(key_data_t *key)
101 {
102  return keystate(key_state_state(key_data_cached_ds(key)),
105  key_data_ds_at_parent(key));
106 }
107 
112 const char*
114 {
115  int z,k;
116  switch(key_data_role(key)) {
117  case KEY_DATA_ROLE_KSK:
118  return statenames[kskstate(key)];
119  case KEY_DATA_ROLE_ZSK:
120  return statenames[zskstate(key)];
121  case KEY_DATA_ROLE_CSK:
122  k = kskstate(key);
123  z = zskstate(key);
124  if (k != z) return statenames[KS_MIX];
125  return statenames[k];
126  default:
127  return statenames[KS_UNK];
128  }
129 }
130 
135 static char*
136 map_keytime(const zone_db_t *zone, const key_data_t *key)
137 {
138  char ct[26];
139  struct tm srtm;
140  time_t t;
141 
142  switch(key_data_ds_at_parent(key)) {
144  return strdup("waiting for ds-submit");
146  return strdup("waiting for ds-seen");
148  return strdup("waiting for ds-retract");
150  return strdup("waiting for ds-gone");
151  default:
152  break;
153  }
154  if (zone_db_next_change(zone) < 0)
155  return strdup("-");
156  else if (zone_db_next_change(zone) < time_now())
157  return strdup("now");
158 
159  t = (time_t)zone_db_next_change(zone);
160  localtime_r(&t, &srtm);
161  strftime(ct, 26, "%Y-%m-%d %H:%M:%S", &srtm);
162  return strdup(ct);
163 }
164 
165 static int
166 perform_keystate_list(int sockfd, db_connection_t *dbconn,
167  const char* zonename, const char* keytype, const char* keystate,
168  void (printheader)(int sockfd),
169  void (printkey)(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmKey)) {
170  key_data_list_t* key_list;
171  key_data_t* key;
172  zone_db_t *zone = NULL;
173  char* tchange;
174  hsm_key_t *hsmkey;
175  int cmp;
176 
177  if (!(key_list = key_data_list_new_get(dbconn))) {
178  client_printf_err(sockfd, "Unable to get list of keys, memory "
179  "allocation or database error!\n");
180  return 1;
181  }
182 
183  if (printheader) {
184  (*printheader)(sockfd);
185  }
186 
187  while ((key = key_data_list_get_next(key_list))) {
188  /* only refetches zone if different from previous */
189  if (zone
190  && (db_value_cmp(zone_db_id(zone), key_data_zone_id(key), &cmp)
191  || cmp)) {
192  zone_db_free(zone);
193  zone = NULL;
194  }
195  if (!zone) {
196  zone = key_data_get_zone(key);
197  }
198  hsmkey = key_data_get_hsm_key(key);
200  tchange = map_keytime(zone, key); /* allocs */
201  if ((printkey != NULL) && (!zonename || !strcmp(zone_db_name(zone), zonename)) && (!keytype || !strcasecmp(keytype,key_data_role_text(key))) && (!keystate || !strcasecmp(keystate, map_keystate(key))))
202  (*printkey)(sockfd, zone, key, tchange, hsmkey);
203  free(tchange);
204  hsm_key_free(hsmkey);
205  key_data_free(key);
206  }
207  zone_db_free(zone);
208  key_data_list_free(key_list);
209  return 0;
210 }
211 
212 static void
213 usage(int sockfd)
214 {
215  client_printf(sockfd,
216  "key list\n"
217  " [--verbose] aka -v\n"
218  " [--debug] aka -d\n"
219  " [--parsable] aka -p\n"
220  " [--zone] aka -z \n"
221  " [--keystate | --all] aka -k | -a \n"
222  );
223 }
224 
225 static void
226 help(int sockfd)
227 {
228  client_printf(sockfd,
229  "List the keys in the enforcer database.\n"
230  "\nOptions:\n"
231  "verbose also show additional key parameters\n"
232  "debug print information about the keystate\n"
233  "parsable output machine parsable list\n"
234  "zone limit the output to the specific zone\n"
235  "keytype limit the output to the given type, can be ZSK, KSK, or CSK\n"
236  "keystate limit the output to the given state\n"
237  "all print keys in all states (including generate) \n\n");
238 }
239 
240 static void
241 printcompatheader(int sockfd) {
242  client_printf(sockfd, "Keys:\n");
243  client_printf(sockfd, "%-31s %-8s %-9s %s\n", "Zone:", "Keytype:", "State:",
244  "Date of next transition:");
245 }
246 
247 static void
248 printcompatkey(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
249  (void)hsmkey;
250  client_printf(sockfd,
251  "%-31s %-8s %-9s %s\n",
252  zone_db_name(zone),
253  key_data_role_text(key),
254  map_keystate(key),
255  tchange);
256 }
257 
258 static void
259 printverboseheader(int sockfd) {
260  client_printf(sockfd, "Keys:\n");
261  client_printf(sockfd, "%-31s %-8s %-9s %-24s %-5s %-10s %-32s %-11s %s\n", "Zone:", "Keytype:", "State:",
262  "Date of next transition:", "Size:", "Algorithm:", "CKA_ID:",
263  "Repository:", "KeyTag:");
264 }
265 
266 static void
267 printverbosekey(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
268  (void)tchange;
269  client_printf(sockfd,
270  "%-31s %-8s %-9s %-24s %-5d %-10d %-32s %-11s %d\n",
271  zone_db_name(zone),
272  key_data_role_text(key),
273  map_keystate(key),
274  tchange,
275  hsm_key_bits(hsmkey),
276  hsm_key_algorithm(hsmkey),
277  hsm_key_locator(hsmkey),
278  hsm_key_repository(hsmkey),
279  key_data_keytag(key));
280 }
281 
282 static void
283 printverboseparsablekey(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
284  client_printf(sockfd,
285  "%s;%s;%s;%s;%d;%d;%s;%s;%d\n",
286  zone_db_name(zone),
287  key_data_role_text(key),
288  map_keystate(key),
289  tchange,
290  hsm_key_bits(hsmkey),
291  hsm_key_algorithm(hsmkey),
292  hsm_key_locator(hsmkey),
293  hsm_key_repository(hsmkey),
294  key_data_keytag(key));
295 }
296 
297 static void
298 printdebugheader(int sockfd) {
299  client_printf(sockfd,
300  "Keys:\nZone: Key role: "
301  "DS: DNSKEY: RRSIGDNSKEY: RRSIG: "
302  "Pub: Act: Id:\n");
303 }
304 
305 static void
306 printdebugkey(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
307  (void)tchange;
308  client_printf(sockfd,
309  "%-31s %-13s %-12s %-12s %-12s %-12s %d %4d %s\n",
310  zone_db_name(zone),
311  key_data_role_text(key),
316  key_data_publish(key),
318  hsm_key_locator(hsmkey));
319 }
320 
321 static void
322 printdebugparsablekey(int sockfd, zone_db_t* zone, key_data_t* key, char* tchange, hsm_key_t* hsmkey) {
323  (void)tchange;
324  client_printf(sockfd,
325  "%s;%s;%s;%s;%s;%s;%d;%d;%s\n",
326  zone_db_name(zone),
327  key_data_role_text(key),
332  key_data_publish(key),
334  hsm_key_locator(hsmkey));
335 }
336 
337 static int
338 run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
339 {
340  char buf[ODS_SE_MAXLINE];
341  #define NARGV 12
342  const char *argv[NARGV];
343  int success, argIndex;
344  int argc = 0, bVerbose = 0, bDebug = 0, bParsable = 0, bAll = 0;
345  int long_index = 0, opt = 0;
346  const char* keytype = NULL;
347  const char* keystate = NULL;
348  const char* zonename = NULL;
349  db_connection_t* dbconn = getconnectioncontext(context);
350 
351  static struct option long_options[] = {
352  {"verbose", no_argument, 0, 'v'},
353  {"debug", no_argument, 0, 'd'},
354  {"parsable", no_argument, 0, 'p'},
355  {"zone", required_argument, 0, 'z'},
356  {"keytype", required_argument, 0, 't'},
357  {"keystate", required_argument, 0, 'e'},
358  {"all", no_argument, 0, 'a'},
359  {0, 0, 0, 0}
360  };
361 
362  ods_log_debug("[%s] %s command", module_str, key_list_funcblock.cmdname);
363 
364  /* Use buf as an intermediate buffer for the command. */
365  strncpy(buf, cmd, sizeof (buf));
366  buf[sizeof (buf) - 1] = '\0';
367 
368  /* separate the arguments */
369  argc = ods_str_explode(buf, NARGV, argv);
370  if (argc == -1) {
371  ods_log_error("[%s] too many arguments for %s command",
372  module_str, key_list_funcblock.cmdname);
373  client_printf_err(sockfd, "too many arguments\n");
374  return -1;
375  }
376  optind = 0;
377  while ((opt = getopt_long(argc, (char* const*)argv, "vdpz:t:e:a", long_options, &long_index) ) != -1) {
378  switch (opt) {
379  case 'v':
380  bVerbose = 1;
381  break;
382  case 'd':
383  bDebug = 1;
384  break;
385  case 'p':
386  bParsable = 1;
387  break;
388  case 'z':
389  zonename = optarg;
390  break;
391  case 't':
392  keytype = optarg;
393  break;
394  case 'e':
395  keystate = optarg;
396  break;
397  case 'a':
398  bAll = 1;
399  break;
400  default:
401  client_printf_err(sockfd, "unknown arguments\n");
402  ods_log_error("[%s] unknown arguments for %s command",
403  module_str, key_list_funcblock.cmdname);
404  return -1;
405  }
406  }
407 
408  if (keystate != NULL && bAll) {
409  client_printf(sockfd, "Error: --keystate and --all option cannot be given together\n");
410  return -1;
411  }
412 
413  if (bDebug) {
414  if (bParsable) {
415  success = perform_keystate_list(sockfd, dbconn, zonename, keytype, keystate, NULL, &printdebugparsablekey);
416  } else {
417  success = perform_keystate_list(sockfd, dbconn, zonename, keytype, keystate, &printdebugheader, &printdebugkey);
418  }
419  } else if (bVerbose) {
420  if (bParsable) {
421  success = perform_keystate_list(sockfd, dbconn, zonename, keytype, keystate, NULL, &printverboseparsablekey);
422  } else {
423  success = perform_keystate_list(sockfd, dbconn, zonename, keytype, keystate, &printverboseheader, &printverbosekey);
424  }
425  } else {
426  if (bParsable)
427  client_printf_err(sockfd, "-p option only available in combination with -v and -d.\n");
428  success = perform_keystate_list(sockfd, dbconn, zonename, keytype, keystate, &printcompatheader, &printcompatkey);
429  }
430 
431  return success;
432 }
433 
434 struct cmd_func_block key_list_funcblock = {
435  "key list", &usage, &help, NULL, &run
436 };
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 zone_db_free(zone_db_t *zone)
Definition: zone_db.c:325
hsm_key_t * key_data_get_hsm_key(const key_data_t *key_data)
Definition: key_data.c:649
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
struct cmd_func_block key_list_funcblock
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
#define OMN
unsigned int key_data_introducing(const key_data_t *key_data)
Definition: key_data.c:727
db_connection_t * getconnectioncontext(cmdhandler_ctx_type *context)
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[]
int zone_db_next_change(const zone_db_t *zone)
Definition: zone_db.c:806
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
const char * zone_db_name(const zone_db_t *zone)
Definition: zone_db.c:782
#define UNR
const char * hsm_key_locator(const hsm_key_t *hsm_key)
Definition: hsm_key.c:520
key_state_state
Definition: key_state.h:49
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
zone_db_t * key_data_get_zone(const key_data_t *key_data)
Definition: key_data.c:569
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
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
#define HID
const db_value_t * zone_db_id(const zone_db_t *zone)
Definition: zone_db.c:728
unsigned int hsm_key_bits(const hsm_key_t *hsm_key)
Definition: hsm_key.c:536
#define RUM