1 /*
2 * Copyright (c) 2014 .SE (The Internet Infrastructure Foundation).
3 * Copyright (c) 2014 OpenDNSSEC AB (svb)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 #include "log.h"
30 #include "str.h"
31 #include "clientpipe.h"
32 #include "duration.h"
33 #include "db/key_data.h"
34 #include "db/hsm_key.h"
35 #include "utils/kc_helper.h"
36
37 #include "signconf/signconf_xml.h"
38
39 #include <libxml/parser.h>
40 #include <libxml/tree.h>
41 #include <limits.h>
42 #include <unistd.h>
43
44 /**
45 * Export the signconf XML for the given zone that uses the given policy.
46 * \param[in] sockfd a socket fd.
47 * \param[in] policy a policy_t pointer.
48 * \param[in] zone a zone_db_t pointer.
49 * \param[in] force if non-zero it will force the export for all zones even if
50 * there are no updates for the zones.
51 * \return SIGNCONF_EXPORT_ERR_* on error, otherwise SIGNCONF_EXPORT_OK or
52 * SIGNCONF_EXPORT_NO_CHANGE.
53 */
54 static int signconf_xml_export(int sockfd, const policy_t* policy, zone_db_t* zone, int force);
55
56 int
signconf_export_zone(char const * zonename,db_connection_t * dbconn)57 signconf_export_zone(char const *zonename, db_connection_t* dbconn)
58 {
59 zone_db_t* zone;
60 int ret;
61 policy_t* policy;
62
63 zone = zone_db_new_get_by_name(dbconn, zonename);
64 if (!zone) {
65 ods_log_error("[signconf_export] Unable to fetch zone %s from"
66 " database", zonename);
67 return SIGNCONF_EXPORT_ERR_DATABASE;
68 }
69 policy = zone_db_get_policy(zone);
70 if (!policy) {
71 ods_log_error("[signconf_export] Unable to fetch policy for zone"
72 " %s from database", zonename);
73 zone_db_free(zone);
74 return SIGNCONF_EXPORT_ERR_DATABASE;
75 }
76
77 /* We always force. Since now it is scheduled per zone */
78 ret = signconf_xml_export(-1, policy, zone, 1);
79 policy_free(policy);
80 zone_db_free(zone);
81 return ret;
82 }
83
signconf_export_all(int sockfd,const db_connection_t * connection,int force)84 int signconf_export_all(int sockfd, const db_connection_t* connection, int force) {
85 zone_list_db_t* zone_list;
86 zone_db_t* zone;
87 int ret;
88 policy_t *policy = NULL;
89 int cmp;
90 int change = 0;
91
92 if (!connection) {
93 return SIGNCONF_EXPORT_ERR_ARGS;
94 }
95
96 if (!(zone_list = zone_list_db_new(connection))
97 || zone_list_db_get(zone_list))
98 {
99 if (zone_list) {
100 zone_list_db_free(zone_list);
101 return SIGNCONF_EXPORT_ERR_DATABASE;
102 }
103 return SIGNCONF_EXPORT_ERR_MEMORY;
104 }
105
106 for (zone = zone_list_db_get_next(zone_list); zone; zone = zone_list_db_get_next(zone_list)) {
107 if (policy) {
108 /*
109 * If we already have a policy object; If policy_id compare fails
110 * or if they are not the same, free the policy object so we will
111 * later retrieve the correct policy
112 */
113 if (db_value_cmp(policy_id(policy), zone_db_policy_id(zone), &cmp)
114 || cmp)
115 {
116 policy_free(policy);
117 policy = NULL;
118 }
119 }
120 if (!policy) {
121 if (!(policy = zone_db_get_policy(zone))) {
122 zone_db_free(zone);
123 zone_list_db_free(zone_list);
124 return SIGNCONF_EXPORT_ERR_DATABASE;
125 }
126 }
127
128 ret = signconf_xml_export(sockfd, policy, zone, force);
129 if (ret == SIGNCONF_EXPORT_OK) {
130 change = 1;
131 }
132 else if (ret != SIGNCONF_EXPORT_NO_CHANGE) {
133 zone_db_free(zone);
134 zone_list_db_free(zone_list);
135 return ret;
136 }
137 zone_db_free(zone);
138 }
139 policy_free(policy);
140 zone_list_db_free(zone_list);
141
142 if (change) {
143 return SIGNCONF_EXPORT_OK;
144 }
145 return SIGNCONF_EXPORT_NO_CHANGE;
146 }
147
__free(char ** p)148 static int __free(char **p) {
149 if (!p || !*p) {
150 return 1;
151 }
152 free(*p);
153 *p = NULL;
154 return 0;
155 }
156
signconf_xml_export(int sockfd,const policy_t * policy,zone_db_t * zone,int force)157 static int signconf_xml_export(int sockfd, const policy_t* policy, zone_db_t* zone, int force) {
158 char path[PATH_MAX];
159 xmlDocPtr doc;
160 xmlNodePtr root;
161 xmlNodePtr node;
162 xmlNodePtr node2;
163 xmlNodePtr node3;
164 xmlNodePtr node4;
165 xmlNodePtr node5;
166 xmlNodePtr keys;
167 duration_type* duration;
168 char* duration_text = NULL;
169 char text[1024];
170 key_data_list_t* key_data_list;
171 const key_data_t* key_data;
172 hsm_key_t* hsm_key;
173 int error;
174
175 if (!policy) {
176 return SIGNCONF_EXPORT_ERR_ARGS;
177 }
178 if (!zone) {
179 return SIGNCONF_EXPORT_ERR_ARGS;
180 }
181
182 if (!force && !zone_db_signconf_needs_writing(zone)) {
183 return SIGNCONF_EXPORT_NO_CHANGE;
184 }
185
186 if (snprintf(path, sizeof(path), "%s.new", zone_db_signconf_path(zone)) >= (int)sizeof(path)) {
187 ods_log_error("[signconf_export] Unable to write updated XML for zone %s, path to long!", zone_db_name(zone));
188 if (sockfd > -1) client_printf_err(sockfd, "Unable to write updated XML for zone %s, path to long!\n", zone_db_name(zone));
189 return SIGNCONF_EXPORT_ERR_MEMORY;
190 }
191
192 if (!(duration = duration_create())) {
193 ods_log_error("[signconf_export] Unable to process signconf for zone %s, memory allocation error!", zone_db_name(zone));
194 if (sockfd > -1) client_printf_err(sockfd, "Unable to process signconf for zone %s, memory allocation error!\n", zone_db_name(zone));
195 return SIGNCONF_EXPORT_ERR_MEMORY;
196 }
197
198 if (!(doc = xmlNewDoc((xmlChar*)"1.0"))
199 || !(root = xmlNewNode(NULL, (xmlChar*)"SignerConfiguration"))
200 || !(node = xmlNewChild(root, NULL, (xmlChar*)"Zone", NULL)))
201 {
202 ods_log_error("[signconf_export] Unable to create XML elements for zone %s, memory allocation error!", zone_db_name(zone));
203 if (sockfd > -1) client_printf_err(sockfd, "Unable to create XML elements for zone %s, memory allocation error!\n", zone_db_name(zone));
204 if (doc) {
205 xmlFreeDoc(doc);
206 }
207 duration_cleanup(duration);
208 return SIGNCONF_EXPORT_ERR_MEMORY;
209 }
210
211 xmlDocSetRootElement(doc, root);
212
213 error = 1;
214 if (!xmlNewProp(node, (xmlChar*)"name", (xmlChar*)zone_db_name(zone))
215 || !(error = 26)
216 || (policy_passthrough(policy) && !(node2 = xmlNewChild(node, NULL, (xmlChar*)"Passthrough", NULL)))
217 || !(error = 2)
218 || !(node2 = xmlNewChild(node, NULL, (xmlChar*)"Signatures", NULL))
219 || !(error = 3)
220 || duration_set_time(duration, policy_signatures_resign(policy))
221 || !(duration_text = duration2string(duration))
222 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Resign", (xmlChar*)duration_text))
223 || __free(&duration_text)
224 || !(error = 4)
225 || duration_set_time(duration, policy_signatures_refresh(policy))
226 || !(duration_text = duration2string(duration))
227 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Refresh", (xmlChar*)duration_text))
228 || __free(&duration_text)
229 || !(error = 5)
230 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Validity", NULL))
231 || !(error = 6)
232 || duration_set_time(duration, policy_signatures_validity_default(policy))
233 || !(duration_text = duration2string(duration))
234 || !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"Default", (xmlChar*)duration_text))
235 || __free(&duration_text)
236 || !(error = 7)
237 || duration_set_time(duration, policy_signatures_validity_denial(policy))
238 || !(duration_text = duration2string(duration))
239 || !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"Denial", (xmlChar*)duration_text))
240 || __free(&duration_text)
241 || !(error = 8)
242 || (policy_signatures_validity_keyset(policy) > 0 ?
243 duration_set_time(duration, policy_signatures_validity_keyset(policy))
244 || !(duration_text = duration2string(duration))
245 || !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"Keyset", (xmlChar*)duration_text))
246 || __free(&duration_text)
247 || !(error = 100) : 0)
248 || duration_set_time(duration, policy_signatures_jitter(policy))
249 || !(duration_text = duration2string(duration))
250 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Jitter", (xmlChar*)duration_text))
251 || __free(&duration_text)
252 || !(error = 9)
253 || duration_set_time(duration, policy_signatures_inception_offset(policy))
254 || !(duration_text = duration2string(duration))
255 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"InceptionOffset", (xmlChar*)duration_text))
256 || __free(&duration_text)
257 || !(error = 10)
258 || (policy_signatures_max_zone_ttl(policy)
259 && (duration_set_time(duration, policy_signatures_max_zone_ttl(policy))
260 || !(duration_text = duration2string(duration))
261 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"MaxZoneTTL", (xmlChar*)duration_text))
262 || __free(&duration_text)))
263
264 || !(error = 11)
265 || !(node2 = xmlNewChild(node, NULL, (xmlChar*)"Denial", NULL))
266 || !(error = 12)
267 || (policy_denial_type(policy) == POLICY_DENIAL_TYPE_NSEC
268 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"NSEC", NULL)))
269 || !(error = 13)
270 || (policy_denial_type(policy) == POLICY_DENIAL_TYPE_NSEC3
271 && (!(node3 = xmlNewChild(node2, NULL, (xmlChar*)"NSEC3", NULL))
272 || !(error = 14)
273 || (policy_denial_ttl(policy)
274 && (duration_set_time(duration, policy_denial_ttl(policy))
275 || !(duration_text = duration2string(duration))
276 || !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"TTL", (xmlChar*)duration_text))
277 || __free(&duration_text)))
278 || !(error = 15)
279 || (policy_denial_optout(policy)
280 && !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"OptOut", NULL)))
281 || !(error = 16)
282 || !(node4 = xmlNewChild(node3, NULL, (xmlChar*)"Hash", NULL))
283 || !(error = 17)
284 || snprintf(text, sizeof(text), "%u", policy_denial_algorithm(policy)) >= (int)sizeof(text)
285 || !(node5 = xmlNewChild(node4, NULL, (xmlChar*)"Algorithm", (xmlChar*)text))
286 || !(error = 18)
287 || snprintf(text, sizeof(text), "%u", policy_denial_iterations(policy)) >= (int)sizeof(text)
288 || !(node5 = xmlNewChild(node4, NULL, (xmlChar*)"Iterations", (xmlChar*)text))
289 || !(error = 19)
290 || !(node5 = xmlNewChild(node4, NULL, (xmlChar*)"Salt", (xmlChar*)policy_denial_salt(policy)))))
291
292 || !(error = 20)
293 || !(keys = xmlNewChild(node, NULL, (xmlChar*)"Keys", NULL))
294 || !(error = 21)
295 || duration_set_time(duration, policy_keys_ttl(policy))
296 || !(duration_text = duration2string(duration))
297 || !(node3 = xmlNewChild(keys, NULL, (xmlChar*)"TTL", (xmlChar*)duration_text))
298 || __free(&duration_text)
299
300 || !(error = 22)
301 || !(node2 = xmlNewChild(node, NULL, (xmlChar*)"SOA", NULL))
302 || !(error = 23)
303 || duration_set_time(duration, policy_zone_soa_ttl(policy))
304 || !(duration_text = duration2string(duration))
305 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"TTL", (xmlChar*)duration_text))
306 || __free(&duration_text)
307 || !(error = 24)
308 || duration_set_time(duration, policy_zone_soa_minimum(policy))
309 || !(duration_text = duration2string(duration))
310 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Minimum", (xmlChar*)duration_text))
311 || __free(&duration_text)
312 || !(error = 25)
313 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Serial", (xmlChar*)policy_zone_soa_serial_text(policy)))
314 )
315 {
316 ods_log_error("[signconf_export] Unable to create XML elements for zone %s! [%d]", zone_db_name(zone), error);
317 if (sockfd > -1) client_printf_err(sockfd, "Unable to create XML elements for zone %s!\n", zone_db_name(zone));
318 __free(&duration_text);
319 duration_cleanup(duration);
320 xmlFreeDoc(doc);
321 return SIGNCONF_EXPORT_ERR_XML;
322 }
323 __free(&duration_text);
324 duration_cleanup(duration);
325
326 if (!(key_data_list = zone_db_get_keys(zone))) {
327 ods_log_error("[signconf_export] Unable to get keys for zone %s!", zone_db_name(zone));
328 if (sockfd > -1) client_printf_err(sockfd, "Unable to get keys for zone %s!\n", zone_db_name(zone));
329 xmlFreeDoc(doc);
330 return SIGNCONF_EXPORT_ERR_DATABASE;
331 }
332
333 for (key_data = key_data_list_next(key_data_list); key_data; key_data = key_data_list_next(key_data_list)) {
334 if (!(hsm_key = key_data_get_hsm_key(key_data))) {
335 ods_log_error("[signconf_export] Unable to get HSM key from database for zone %s!", zone_db_name(zone));
336 if (sockfd > -1) client_printf_err(sockfd, "Unable to get HSM key from database for zone %s!\n", zone_db_name(zone));
337 key_data_list_free(key_data_list);
338 xmlFreeDoc(doc);
339 return SIGNCONF_EXPORT_ERR_DATABASE;
340 }
341 error = 100;
342 if (!(node2 = xmlNewChild(keys, NULL, (xmlChar*)"Key", NULL))
343 || !(error = 101)
344 || (key_data_role(key_data) == KEY_DATA_ROLE_ZSK
345 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Flags", (xmlChar*)"256")))
346 || !(error = 102)
347 || (key_data_role(key_data) != KEY_DATA_ROLE_ZSK
348 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Flags", (xmlChar*)"257")))
349 || !(error = 103)
350 || snprintf(text, sizeof(text), "%u", key_data_algorithm(key_data)) >= (int)sizeof(text)
351 || !(error = 104)
352 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Algorithm", (xmlChar*)text))
353 || !(error = 105)
354 || !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Locator",(xmlChar*)hsm_key_locator(hsm_key)))
355 || !(error = 106)
356 || (key_data_active_ksk(key_data)
357 && (key_data_role(key_data) == KEY_DATA_ROLE_KSK
358 || key_data_role(key_data) == KEY_DATA_ROLE_CSK)
359 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"KSK", NULL)))
360 || !(error = 107)
361 || (key_data_active_zsk(key_data)
362 && (key_data_role(key_data) == KEY_DATA_ROLE_ZSK
363 || key_data_role(key_data) == KEY_DATA_ROLE_CSK)
364 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"ZSK", NULL)))
365 || !(error = 108)
366 || (key_data_publish(key_data)
367 && !(node3 = xmlNewChild(node2, NULL, (xmlChar*)"Publish", NULL)))
368 /* TODO:
369 * What about <Deactivate/> ?
370 */
371 )
372 {
373 ods_log_error("[signconf_export] Unable to create key XML elements for zone %s! [%d]", zone_db_name(zone), error);
374 if (sockfd > -1) client_printf_err(sockfd, "Unable to create key XML elements for zone %s!\n", zone_db_name(zone));
375 hsm_key_free(hsm_key);
376 key_data_list_free(key_data_list);
377 xmlFreeDoc(doc);
378 return SIGNCONF_EXPORT_ERR_XML;
379 }
380 hsm_key_free(hsm_key);
381 }
382 key_data_list_free(key_data_list);
383
384 unlink(path);
385 if (xmlSaveFormatFileEnc(path, doc, "UTF-8", 1) == -1) {
386 ods_log_error("[signconf_export] Unable to write signconf for zone %s, LibXML error!", zone_db_name(zone));
387 if (sockfd > -1) client_printf_err(sockfd, "Unable to write signconf for zone %s, LibXML error!\n", zone_db_name(zone));
388 xmlFreeDoc(doc);
389 return SIGNCONF_EXPORT_ERR_FILE;
390 }
391 xmlFreeDoc(doc);
392
393 if (check_rng(path, OPENDNSSEC_SCHEMA_DIR "/signconf.rng", 0)) {
394 ods_log_error("[signconf_export] Unable to validate the exported signconf XML for zone %s!", zone_db_name(zone));
395 if (sockfd > -1) client_printf_err(sockfd, "Unable to validate the exported signconf XML for zone %s!\n", zone_db_name(zone));
396 return SIGNCONF_EXPORT_ERR_XML;
397 }
398
399 if (rename(path, zone_db_signconf_path(zone))) {
400 ods_log_error("[signconf_export] Unable to write signconf for zone %s, rename failed!", zone_db_name(zone));
401 if (sockfd > -1) client_printf_err(sockfd, "Unable to write signconf for zone %s, rename failed!\n", zone_db_name(zone));
402 unlink(path);
403 return SIGNCONF_EXPORT_ERR_FILE;
404 }
405
406 zone_db_set_signconf_needs_writing(zone, 0);
407 zone_db_update(zone);
408
409 return SIGNCONF_EXPORT_OK;
410 }
411