1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  * Parsing DNS Adapter.
29  *
30  */
31 
32 #include "parser/addnsparser.h"
33 #include "log.h"
34 
35 #include <libxml/xpath.h>
36 #include <libxml/xmlreader.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 static const char* parser_str = "parser";
41 
42 
43 /**
44  * Parse the remote servers.
45  *
46  */
47 static acl_type*
parse_addns_remote(const char * filename,tsig_type * tsig,char * expr)48 parse_addns_remote(const char* filename,
49     tsig_type* tsig, char* expr)
50 {
51     acl_type* acl = NULL;
52     acl_type* new_acl = NULL;
53     int i = 0;
54     char* address = NULL;
55     char* port = NULL;
56     char* key = NULL;
57     xmlDocPtr doc = NULL;
58     xmlXPathContextPtr xpathCtx = NULL;
59     xmlXPathObjectPtr xpathObj = NULL;
60     xmlNode* curNode = NULL;
61     xmlChar* xexpr = NULL;
62 
63     if (!filename || !expr) {
64         return NULL;
65     }
66     /* Load XML document */
67     doc = xmlParseFile(filename);
68     if (doc == NULL) {
69         ods_log_error("[%s] could not parse %s: xmlParseFile() failed",
70             parser_str, expr);
71         return NULL;
72     }
73     /* Create xpath evaluation context */
74     xpathCtx = xmlXPathNewContext(doc);
75     if(xpathCtx == NULL) {
76         xmlFreeDoc(doc);
77         ods_log_error("[%s] could not parse %s: xmlXPathNewContext() failed",
78             parser_str, expr);
79         return NULL;
80     }
81     /* Evaluate xpath expression */
82     xexpr = (xmlChar*) expr;
83     xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
84     if(xpathObj == NULL) {
85         xmlXPathFreeContext(xpathCtx);
86         xmlFreeDoc(doc);
87         ods_log_error("[%s] could not parse %s: xmlXPathEvalExpression() "
88             "failed", parser_str, expr);
89         return NULL;
90     }
91     /* Parse interfaces */
92     if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
93         for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
94             address = NULL;
95             port = NULL;
96             key = NULL;
97 
98             curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
99             while (curNode) {
100                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Address")) {
101                     address = (char *) xmlNodeGetContent(curNode);
102                 } else if (xmlStrEqual(curNode->name,
103                     (const xmlChar *)"Port")) {
104                     port = (char *) xmlNodeGetContent(curNode);
105                 } else if (xmlStrEqual(curNode->name,
106                     (const xmlChar *)"Key")) {
107                     key = (char *) xmlNodeGetContent(curNode);
108                 }
109                 curNode = curNode->next;
110             }
111             if (address) {
112                 new_acl = acl_create(address, port, key, tsig);
113                 if (!new_acl) {
114                    ods_log_error("[%s] unable to add server %s:%s %s to list "
115                        "%s: acl_create() failed", parser_str, address,
116                        port?port:"", key?key:"", (char*) expr);
117                 } else {
118                    new_acl->next = acl;
119                    acl = new_acl;
120                    ods_log_debug("[%s] added server %s:%s %s to list %s",
121                        parser_str, address, port?port:"", key?key:"",
122                        (char*) expr);
123                 }
124             }
125             free((void*)address);
126             free((void*)port);
127             free((void*)key);
128         }
129     }
130     xmlXPathFreeObject(xpathObj);
131     xmlXPathFreeContext(xpathCtx);
132     if (doc) {
133         xmlFreeDoc(doc);
134     }
135     return acl;
136 }
137 
138 
139 /**
140  * Parse the ACL interfaces.
141  *
142  */
143 static acl_type*
parse_addns_acl(const char * filename,tsig_type * tsig,char * expr)144 parse_addns_acl(const char* filename,
145     tsig_type* tsig, char* expr)
146 {
147     acl_type* acl = NULL;
148     acl_type* new_acl = NULL;
149     int i = 0;
150     char* prefix = NULL;
151     char* key = NULL;
152     xmlDocPtr doc = NULL;
153     xmlXPathContextPtr xpathCtx = NULL;
154     xmlXPathObjectPtr xpathObj = NULL;
155     xmlNode* curNode = NULL;
156     xmlChar* xexpr = NULL;
157 
158     if (!filename || !expr) {
159         return NULL;
160     }
161     /* Load XML document */
162     doc = xmlParseFile(filename);
163     if (doc == NULL) {
164         ods_log_error("[%s] could not parse %s: xmlParseFile() failed",
165             parser_str, expr);
166         return NULL;
167     }
168     /* Create xpath evaluation context */
169     xpathCtx = xmlXPathNewContext(doc);
170     if(xpathCtx == NULL) {
171         xmlFreeDoc(doc);
172         ods_log_error("[%s] could not parse %s: xmlXPathNewContext() failed",
173             parser_str, expr);
174         return NULL;
175     }
176     /* Evaluate xpath expression */
177     xexpr = (xmlChar*) expr;
178     xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
179     if(xpathObj == NULL) {
180         xmlXPathFreeContext(xpathCtx);
181         xmlFreeDoc(doc);
182         ods_log_error("[%s] could not parse %s: xmlXPathEvalExpression() "
183             "failed", parser_str, expr);
184         return NULL;
185     }
186     /* Parse interfaces */
187     if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
188         for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
189             prefix = NULL;
190             key = NULL;
191 
192             curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
193             while (curNode) {
194                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Prefix")) {
195                     prefix = (char *) xmlNodeGetContent(curNode);
196                 } else if (xmlStrEqual(curNode->name,
197                     (const xmlChar *)"Key")) {
198                     key = (char *) xmlNodeGetContent(curNode);
199                 }
200                 curNode = curNode->next;
201             }
202             if (prefix || key) {
203                 new_acl = acl_create(prefix, NULL, key, tsig);
204                 if (!new_acl) {
205                    ods_log_error("[%s] unable to add acl for %s %s to list "
206                        "%s: acl_create() failed", parser_str, prefix?prefix:"",
207                        key?key:"", (char*) expr);
208                 } else {
209                    new_acl->next = acl;
210                    acl = new_acl;
211                    ods_log_debug("[%s] added %s %s interface to list %s",
212                        parser_str, prefix?prefix:"", key?key:"", (char*) expr);
213                 }
214             }
215             free((void*)prefix);
216             free((void*)key);
217         }
218     }
219     xmlXPathFreeObject(xpathObj);
220     xmlXPathFreeContext(xpathCtx);
221     if (doc) {
222         xmlFreeDoc(doc);
223     }
224     return acl;
225 }
226 
227 
228 /**
229  * Parse the TSIG credentials.
230  *
231  */
232 static tsig_type*
parse_addns_tsig_static(const char * filename,char * expr)233 parse_addns_tsig_static(const char* filename,
234     char* expr)
235 {
236     tsig_type* tsig = NULL;
237     tsig_type* new_tsig = NULL;
238     int i = 0;
239     char* name = NULL;
240     char* algo = NULL;
241     char* secret = NULL;
242     xmlDocPtr doc = NULL;
243     xmlXPathContextPtr xpathCtx = NULL;
244     xmlXPathObjectPtr xpathObj = NULL;
245     xmlNode* curNode = NULL;
246     xmlChar* xexpr = NULL;
247 
248     if (!filename || !expr) {
249         return NULL;
250     }
251     /* Load XML document */
252     doc = xmlParseFile(filename);
253     if (doc == NULL) {
254         ods_log_error("[%s] could not parse %s: xmlParseFile() failed",
255             parser_str, expr);
256         return NULL;
257     }
258     /* Create xpath evaluation context */
259     xpathCtx = xmlXPathNewContext(doc);
260     if(xpathCtx == NULL) {
261         xmlFreeDoc(doc);
262         ods_log_error("[%s] could not parse %s: xmlXPathNewContext() failed",
263             parser_str, expr);
264         return NULL;
265     }
266     /* Evaluate xpath expression */
267     xexpr = (xmlChar*) expr;
268     xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
269     if(xpathObj == NULL) {
270         xmlXPathFreeContext(xpathCtx);
271         xmlFreeDoc(doc);
272         ods_log_error("[%s] could not parse %s: xmlXPathEvalExpression() "
273             "failed", parser_str, expr);
274         return NULL;
275     }
276     /* Parse interfaces */
277     if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
278         for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
279             name = NULL;
280             algo = NULL;
281             secret = NULL;
282 
283             curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
284             while (curNode) {
285                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Name")) {
286                     name = (char *) xmlNodeGetContent(curNode);
287                 } else if (xmlStrEqual(curNode->name,
288                     (const xmlChar *)"Algorithm")) {
289                     algo = (char *) xmlNodeGetContent(curNode);
290                 } else if (xmlStrEqual(curNode->name,
291                     (const xmlChar *)"Secret")) {
292                     secret = (char *) xmlNodeGetContent(curNode);
293                 }
294                 curNode = curNode->next;
295             }
296             if (name && algo && secret) {
297                 new_tsig = tsig_create(name, algo, secret);
298                 if (!new_tsig) {
299                    ods_log_error("[%s] unable to add tsig %s: "
300                        "tsig_create() failed", parser_str, name);
301                 } else {
302                    new_tsig->next = tsig;
303                    tsig = new_tsig;
304                    ods_log_debug("[%s] added %s tsig to list %s",
305                        parser_str, name, (char*) expr);
306                 }
307             }
308             free((void*)name);
309             free((void*)algo);
310             free((void*)secret);
311         }
312     }
313     xmlXPathFreeObject(xpathObj);
314     xmlXPathFreeContext(xpathCtx);
315     if (doc) {
316         xmlFreeDoc(doc);
317     }
318     return tsig;
319 }
320 
321 
322 /**
323  * Parse <RequestTransfer/>.
324  *
325  */
326 acl_type*
parse_addns_request_xfr(const char * filename,tsig_type * tsig)327 parse_addns_request_xfr(const char* filename,
328     tsig_type* tsig)
329 {
330     return parse_addns_remote(filename, tsig,
331         (char *)"//Adapter/DNS/Inbound/RequestTransfer/Remote");
332 }
333 
334 
335 /**
336  * Parse <AllowNotify/>.
337  *
338  */
339 acl_type*
parse_addns_allow_notify(const char * filename,tsig_type * tsig)340 parse_addns_allow_notify(const char* filename,
341     tsig_type* tsig)
342 {
343     return parse_addns_acl(filename, tsig,
344         (char *)"//Adapter/DNS/Inbound/AllowNotify/Peer");
345 }
346 
347 
348 /**
349  * Parse <ProvideTransfer/>.
350  *
351  */
352 acl_type*
parse_addns_provide_xfr(const char * filename,tsig_type * tsig)353 parse_addns_provide_xfr(const char* filename,
354     tsig_type* tsig)
355 {
356     return parse_addns_acl(filename, tsig,
357         (char *)"//Adapter/DNS/Outbound/ProvideTransfer/Peer");
358 }
359 
360 
361 /**
362  * Parse <Notify/>.
363  *
364  */
365 acl_type*
parse_addns_do_notify(const char * filename,tsig_type * tsig)366 parse_addns_do_notify(const char* filename,
367     tsig_type* tsig)
368 {
369     return parse_addns_remote(filename, tsig,
370         (char *)"//Adapter/DNS/Outbound/Notify/Remote");
371 }
372 
373 
374 /**
375  * Parse <TSIG/>.
376  *
377  */
378 tsig_type*
parse_addns_tsig(const char * filename)379 parse_addns_tsig(const char* filename)
380 {
381     return parse_addns_tsig_static(filename,
382         (char *)"//Adapter/DNS/TSIG");
383 }
384 
385