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