OpenDNSSEC-enforcer  2.0.2
keystate_export_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 #include "duration.h"
39 #include "libhsm.h"
40 #include "libhsmdns.h"
41 #include "db/key_data.h"
42 #include "db/db_error.h"
43 
46 
47 static const char *module_str = "keystate_export_cmd";
48 
55 static ldns_rr *
56 get_dnskey(const char *id, const char *zone, const char *keytype, int alg, uint32_t ttl)
57 {
58  libhsm_key_t *key;
59  hsm_sign_params_t *sign_params;
60  ldns_rr *dnskey_rr;
61  /* Code to output the DNSKEY record (stolen from hsmutil) */
62  hsm_ctx_t *hsm_ctx = hsm_create_context();
63  if (!hsm_ctx) {
64  ods_log_error("[%s] Could not connect to HSM", module_str);
65  return NULL;
66  }
67  if (!(key = hsm_find_key_by_id(hsm_ctx, id))) {
68  hsm_destroy_context(hsm_ctx);
69  return NULL;
70  }
71 
72  /* Sign params only need to be kept around
73  * for the hsm_get_dnskey() call. */
74  sign_params = hsm_sign_params_new();
75  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone);
76  sign_params->algorithm = (ldns_algorithm) alg;
77  sign_params->flags = LDNS_KEY_ZONE_KEY;
78 
79  if (keytype && !strcasecmp(keytype, "KSK"))
80  sign_params->flags = sign_params->flags | LDNS_KEY_SEP_KEY;
81 
82  /* Get the DNSKEY record */
83  dnskey_rr = hsm_get_dnskey(hsm_ctx, key, sign_params);
84 
85  free(key);
86  hsm_sign_params_free(sign_params);
87  hsm_destroy_context(hsm_ctx);
88 
89  /* Override the TTL in the dnskey rr */
90  if (ttl) ldns_rr_set_ttl(dnskey_rr, ttl);
91 
92  return dnskey_rr;
93 }
94 
105 static int
106 print_ds_from_id(int sockfd, key_data_t *key, const char *zone,
107  const char* state, int bind_style)
108 {
109  ldns_rr *dnskey_rr;
110  ldns_rr *ds_sha_rr;
111  int ttl = 0;
112  const char *locator;
113  char *rrstr;
114 
115  assert(key);
116  assert(zone);
117 
118  locator = hsm_key_locator(key_data_hsm_key(key));
119  if (!locator) return 1;
120  /* This fetches the states from the DB, I'm only assuming they get
121  * cleaned up when 'key' is cleaned(?) */
122  if (key_data_cache_key_states(key) != DB_OK)
123  return 1;
124 
126 
127  dnskey_rr = get_dnskey(locator, zone, key_data_role_text(key), key_data_algorithm(key), ttl);
128  if (!dnskey_rr) return 1;
129 
130  if (bind_style) {
131  ldns_rr_set_ttl(dnskey_rr, key_state_ttl (key_data_cached_ds(key)));
132  ds_sha_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
133  rrstr = ldns_rr2str(ds_sha_rr);
134  ldns_rr_free(ds_sha_rr);
135  /* TODO log error on failure */
136  (void)client_printf(sockfd, ";%s %s DS record (SHA1):\n%s", state, key_data_role_text(key), rrstr);
137  LDNS_FREE(rrstr);
138 
139  ds_sha_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
140  rrstr = ldns_rr2str(ds_sha_rr);
141  ldns_rr_free(ds_sha_rr);
142  /* TODO log error on failure */
143  (void)client_printf(sockfd, ";%s %s DS record (SHA256):\n%s", state, key_data_role_text(key), rrstr);
144  LDNS_FREE(rrstr);
145  } else {
146  rrstr = ldns_rr2str(dnskey_rr);
147  /* TODO log error on failure */
148  (void)client_printf(sockfd, "%s", rrstr);
149  LDNS_FREE(rrstr);
150  }
151 
152  ldns_rr_free(dnskey_rr);
153  return 0;
154 }
155 
156 static int
157 perform_keystate_export(int sockfd, db_connection_t *dbconn,
158  const char *zonename, const char *keytype, const char *keystate, int all, int bind_style)
159 {
160  key_data_list_t *key_list = NULL;
161  key_data_t *key;
162  zone_t *zone = NULL;
163  db_clause_list_t* clause_list = NULL;
164  const char *azonename = NULL;
165 
166  /* Find all keys related to zonename */
167  if (all == 0) {
168  if (!(key_list = key_data_list_new(dbconn)) ||
169  !(clause_list = db_clause_list_new()) ||
170  !(zone = zone_new_get_by_name(dbconn, zonename)) ||
171  !key_data_zone_id_clause(clause_list, zone_id(zone)) ||
172  key_data_list_get_by_clauses(key_list, clause_list))
173  {
174  key_data_list_free(key_list);
175  db_clause_list_free(clause_list);
176  zone_free(zone);
177  ods_log_error("[%s] Error fetching from database", module_str);
178  return 1;
179  }
180  db_clause_list_free(clause_list);
181  zone_free(zone);
182  }
183  if (all && !(key_list = key_data_list_new_get(dbconn))) {
184  client_printf_err(sockfd, "Unable to get list of keys, memory allocation or database error!\n");
185  return 1;
186  }
187 
188  /* Print data*/
189  while ((key = key_data_list_get_next(key_list))) {
190  if (keytype && strcasecmp(key_data_role_text(key), keytype)) {
191  key_data_free(key);
192  continue;
193  }
194  if (keystate && strcasecmp(map_keystate(key), keystate)) {
195  key_data_free(key);
196  continue;
197  }
198  if (!keytype && !keystate &&
203  {
204  key_data_free(key);
205  continue;
206  }
207 
208  if (all && (!(zone = zone_new (dbconn)) || (zone_get_by_id(zone, key_data_zone_id(key))) || !(azonename = zone_name(zone)))) {
209  ods_log_error("[%s] Error fetching from database", module_str);
210  client_printf_err(sockfd, "Error fetching from database \n");
211  }
212 
213  /* check return code TODO */
214  if (key_data_cache_hsm_key(key) == DB_OK) {
215  if (print_ds_from_id(sockfd, key, (const char*)azonename?azonename:zonename, (const char*)map_keystate(key), bind_style)) {
216  ods_log_error("[%s] Error in print_ds_from_id", module_str);
217  client_printf_err(sockfd, "Error in print_ds_from_id \n");
218  }
219 
220  } else {
221  ods_log_error("[%s] Error fetching from database", module_str);
222  client_printf_err(sockfd, "Error fetching from database \n");
223  }
224  key_data_free(key);
225 
226  if (all)
227  zone_free(zone);
228  }
229  key_data_list_free(key_list);
230  return 0;
231 }
232 
233 static void
234 usage(int sockfd)
235 {
236  client_printf(sockfd,
237  "key export\n"
238  " --zone <zone> | --all aka -z | -a \n"
239  " [--keystate <state>] aka -e\n"
240  " [--keytype <type>] aka -t \n"
241  " [--ds] aka -d\n"
242  );
243 }
244 
245 static void
246 help(int sockfd)
247 {
248  client_printf(sockfd,
249  "Export DNSKEY(s) for a given zone or all of them from the database.\n"
250  "\nOptions:\n"
251  "zone|all name of the zone or all of them\n"
252  "keystate limit the output to a given state\n"
253  "keytype limit the output to a given type, can be ZSK, KSK, or CSK\n"
254  "ds export DS in BIND format which can be used for upload to a registry\n\n");
255 }
256 
257 static int
258 handles(const char *cmd, ssize_t n)
259 {
260  return ods_check_command(cmd, n, key_export_funcblock()->cmdname)?1:0;
261 }
262 
263 static int
264 run(int sockfd, engine_type* engine, const char *cmd, ssize_t n,
265  db_connection_t *dbconn)
266 {
267  #define NARGV 8
268  char buf[ODS_SE_MAXLINE];
269  const char *argv[NARGV];
270  int argc;
271  const char *zonename = NULL;
272  const char* keytype = NULL;
273  const char* keystate = NULL;
274  zone_t * zone = NULL;
275  int all = 0;
276  (void)engine;
277 
278  ods_log_debug("[%s] %s command", module_str, key_export_funcblock()->cmdname);
279  cmd = ods_check_command(cmd, n, key_export_funcblock()->cmdname);
280 
281  /* Use buf as an intermediate buffer for the command.*/
282  strncpy(buf, cmd, sizeof(buf));
283  buf[sizeof(buf)-1] = '\0';
284 
285  /* separate the arguments*/
286  argc = ods_str_explode(buf, NARGV, argv);
287  if (argc > NARGV) {
288  ods_log_error("[%s] too many arguments for %s command",
289  module_str, key_export_funcblock()->cmdname);
290  client_printf_err(sockfd,"too many arguments\n");
291  return -1;
292  }
293 
294  bool bds = 0;
295  (void)ods_find_arg_and_param(&argc,argv,"zone","z",&zonename);
296  (void)ods_find_arg_and_param(&argc, argv, "keytype", "t", &keytype);
297  (void)ods_find_arg_and_param(&argc, argv, "keystate", "e", &keystate);
298  all = ods_find_arg(&argc, argv, "all", "a") > -1 ? 1 : 0;
299 
300  if (keytype) {
301  if (strcasecmp(keytype, "KSK") && strcasecmp(keytype, "ZSK") && strcasecmp(keytype, "CSK")) {
302  ods_log_error("[%s] unknown keytype, should be one of KSK, ZSK, or CSK", module_str);
303  client_printf_err(sockfd, "unknown keytype, should be one of KSK, ZSK, or CSK\n");
304  return -1;
305  }
306  }
307 
308  if (keystate) {
309  if (strcasecmp(keystate, "generate") && strcasecmp(keystate, "publish") && strcasecmp(keystate, "ready") && strcasecmp(keystate, "active") && strcasecmp(keystate, "retire") && strcasecmp(keystate, "revoke")) {
310  ods_log_error("[%s] unknown keystate", module_str);
311  client_printf_err(sockfd, "unknown keystate\n");
312  return -1;
313  }
314  }
315 
316  if (ods_find_arg(&argc,argv,"ds","d") >= 0) bds = 1;
317 
318  if (argc) {
319  ods_log_error("[%s] unknown arguments for %s command",
320  module_str, key_export_funcblock()->cmdname);
321  client_printf_err(sockfd,"unknown arguments\n");
322  return -1;
323  }
324 
325  if ((!zonename && !all) || (zonename && all)) {
326  ods_log_error("[%s] expected either --zone or --all for %s command", module_str, key_export_funcblock()->cmdname);
327  client_printf_err(sockfd, "expected either --zone or --all \n");
328  return -1;
329  }
330  if (zonename && !(zone = zone_new_get_by_name(dbconn, zonename))) {
331  ods_log_error("[%s] Unknown zone: %s", module_str, zonename);
332  client_printf_err(sockfd, "Unknown zone: %s\n", zonename);
333  return -1;
334  }
335  free(zone);
336  zone = NULL;
337 
338  /* in 1.4 the default state for ZSK is active */
339  if (keytype && !strcasecmp(keytype, "ZSK") && !keystate)
340  keystate = "active";
341  /* in 1.4 the dafault type is KSK */
342  else if (keystate && !keytype)
343  keytype = "KSK";
344  else if (keytype && !strcasecmp(keytype, "KSK") && !keystate)
345  keytype = NULL;
346 
347  /* perform task immediately */
348  return perform_keystate_export(sockfd, dbconn, zonename, (const char*) keytype, (const char*) keystate, all, bds?1:0);
349 }
350 
351 static struct cmd_func_block funcblock = {
352  "key export", &usage, &help, &handles, &run
353 };
354 
355 struct cmd_func_block*
357 {
358  return &funcblock;
359 }
const char * key_data_role_text(const key_data_t *key_data)
Definition: key_data.c:711
void(* help)(int sockfd)
Definition: cmdhandler.h:64
void ods_log_debug(const char *format,...)
Definition: log.c:41
db_clause_list_t * db_clause_list_new(void)
Definition: db_clause.c:202
int key_data_list_get_by_clauses(key_data_list_t *key_data_list, const db_clause_list_t *clause_list)
Definition: key_data.c:2119
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 zone_get_by_id(zone_t *zone, const db_value_t *id)
Definition: zone.c:1466
int(* run)(int sockfd, struct engine_struct *engine, const char *cmd, ssize_t n, db_connection_t *dbconn)
Definition: cmdhandler.h:79
const char * cmdname
Definition: cmdhandler.h:59
void ods_log_error(const char *format,...)
Definition: log.c:69
#define NARGV
key_data_t * key_data_list_get_next(key_data_list_t *key_data_list)
Definition: key_data.c:2425
void zone_free(zone_t *zone)
Definition: zone.c:325
void db_clause_list_free(db_clause_list_t *clause_list)
Definition: db_clause.c:209
void(* usage)(int sockfd)
Definition: cmdhandler.h:61
db_clause_t * key_data_zone_id_clause(db_clause_list_t *clause_list, const db_value_t *zone_id)
Definition: key_data.c:976
zone_t * zone_new(const db_connection_t *connection)
Definition: zone.c:287
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 * hsm_key_locator(const hsm_key_t *hsm_key)
Definition: hsm_key.c:520
zone_t * zone_new_get_by_name(const db_connection_t *connection, const char *name)
Definition: zone.c:1569
key_data_list_t * key_data_list_new(const db_connection_t *connection)
Definition: key_data.c:1651
struct cmd_func_block * key_export_funcblock(void)
unsigned int key_state_ttl(const key_state_t *key_state)
Definition: key_state.c:409
const char * zone_name(const zone_t *zone)
Definition: zone.c:782
const char * map_keystate(key_data_t *key)
const key_state_t * key_data_cached_ds(key_data_t *key_data)
Definition: key_data_ext.c:60
int key_data_cache_hsm_key(key_data_t *key_data)
Definition: key_data.c:615
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
#define DB_OK
Definition: db_error.h:36
const hsm_key_t * key_data_hsm_key(const key_data_t *key_data)
Definition: key_data.c:638
Definition: zone.h:46
unsigned int key_data_algorithm(const key_data_t *key_data)
Definition: key_data.c:687
int(* handles)(const char *cmd, ssize_t n)
Definition: cmdhandler.h:67