Merge from vendor branch GDB:
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / config.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2001, 2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: config.c,v 1.11.2.6 2004/04/19 23:15:38 marka Exp $ */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <isc/buffer.h>
26 #include <isc/log.h>
27 #include <isc/mem.h>
28 #include <isc/region.h>
29 #include <isc/result.h>
30 #include <isc/sockaddr.h>
31 #include <isc/util.h>
32
33 #include <isccfg/cfg.h>
34
35 #include <dns/fixedname.h>
36 #include <dns/name.h>
37 #include <dns/rdataclass.h>
38 #include <dns/tsig.h>
39 #include <dns/zone.h>
40
41 #include <named/config.h>
42 #include <named/globals.h>
43
44 static char defaultconf[] = "\
45 options {\n\
46 #       blackhole {none;};\n"
47 #ifndef WIN32
48 "       coresize default;\n\
49         datasize default;\n\
50         files default;\n\
51         stacksize default;\n"
52 #endif
53 "       deallocate-on-exit true;\n\
54 #       directory <none>\n\
55         dump-file \"named_dump.db\";\n\
56         fake-iquery no;\n\
57         has-old-clients false;\n\
58         heartbeat-interval 60;\n\
59         host-statistics no;\n\
60         interface-interval 60;\n\
61         listen-on {any;};\n\
62         listen-on-v6 {none;};\n\
63         match-mapped-addresses no;\n\
64         memstatistics-file \"named.memstats\";\n\
65         multiple-cnames no;\n\
66 #       named-xfer <obsolete>;\n\
67 #       pid-file \"" NS_LOCALSTATEDIR "/named.pid\"; /* or /lwresd.pid */\n\
68         port 53;\n\
69 "
70 #ifdef PATH_RANDOMDEV
71 "\
72         random-device \"" PATH_RANDOMDEV "\";\n\
73 "
74 #endif
75 "\
76         recursive-clients 1000;\n\
77         rrset-order {order cyclic;};\n\
78         serial-queries 20;\n\
79         serial-query-rate 20;\n\
80         statistics-file \"named.stats\";\n\
81         statistics-interval 60;\n\
82         tcp-clients 100;\n\
83 #       tkey-dhkey <none>\n\
84 #       tkey-gssapi-credential <none>\n\
85 #       tkey-domain <none>\n\
86         transfers-per-ns 2;\n\
87         transfers-in 10;\n\
88         transfers-out 10;\n\
89         treat-cr-as-space true;\n\
90         use-id-pool true;\n\
91         use-ixfr true;\n\
92         version \""VERSION"\";\n\
93 \n\
94         /* view */\n\
95         allow-notify {none;};\n\
96         allow-update-forwarding {none;};\n\
97         allow-recursion {any;};\n\
98         allow-v6-synthesis {none;};\n\
99 #       sortlist <none>\n\
100 #       topology <none>\n\
101         auth-nxdomain false;\n\
102         minimal-responses false;\n\
103         recursion true;\n\
104         provide-ixfr true;\n\
105         request-ixfr true;\n\
106         fetch-glue no;\n\
107         rfc2308-type1 no;\n\
108         additional-from-auth true;\n\
109         additional-from-cache true;\n\
110         query-source address *;\n\
111         query-source-v6 address *;\n\
112         notify-source *;\n\
113         notify-source-v6 *;\n\
114         cleaning-interval 60;\n\
115         min-roots 2;\n\
116         lame-ttl 600;\n\
117         max-ncache-ttl 10800; /* 3 hours */\n\
118         max-cache-ttl 604800; /* 1 week */\n\
119         transfer-format many-answers;\n\
120         max-cache-size 0;\n\
121         check-names master ignore;\n\
122         check-names slave ignore;\n\
123         check-names response ignore;\n\
124 \n\
125         /* zone */\n\
126         allow-query {any;};\n\
127         allow-transfer {any;};\n\
128         notify yes;\n\
129 #       also-notify <none>\n\
130         dialup no;\n\
131 #       forward <none>\n\
132 #       forwarders <none>\n\
133         maintain-ixfr-base no;\n\
134 #       max-ixfr-log-size <obsolete>\n\
135         transfer-source *;\n\
136         transfer-source-v6 *;\n\
137         max-transfer-time-in 120;\n\
138         max-transfer-time-out 120;\n\
139         max-transfer-idle-in 60;\n\
140         max-transfer-idle-out 60;\n\
141         max-retry-time 1209600; /* 2 weeks */\n\
142         min-retry-time 500;\n\
143         max-refresh-time 2419200; /* 4 weeks */\n\
144         min-refresh-time 300;\n\
145         sig-validity-interval 30; /* days */\n\
146         zone-statistics false;\n\
147 };";
148
149 isc_result_t
150 ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
151         isc_buffer_t b;
152
153         isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1);
154         isc_buffer_add(&b, sizeof(defaultconf) - 1);
155         return (cfg_parse_buffer(parser, &b, &cfg_type_namedconf, conf));
156 }
157
158 isc_result_t
159 ns_config_get(cfg_obj_t **maps, const char* name, cfg_obj_t **obj) {
160         int i;
161
162         for (i = 0; ; i++) {
163                 if (maps[i] == NULL)
164                         return (ISC_R_NOTFOUND);
165                 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
166                         return (ISC_R_SUCCESS);
167         }
168 }
169
170 int
171 ns_config_listcount(cfg_obj_t *list) {
172         cfg_listelt_t *e;
173         int i = 0;
174
175         for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e))
176                 i++;
177
178         return (i);
179 }
180
181 isc_result_t
182 ns_config_getclass(cfg_obj_t *classobj, dns_rdataclass_t defclass,
183                    dns_rdataclass_t *classp) {
184         char *str;
185         isc_textregion_t r;
186         isc_result_t result;
187
188         if (!cfg_obj_isstring(classobj)) {
189                 *classp = defclass;
190                 return (ISC_R_SUCCESS);
191         }
192         str = cfg_obj_asstring(classobj);
193         r.base = str;
194         r.length = strlen(str);
195         result = dns_rdataclass_fromtext(classp, &r);
196         if (result != ISC_R_SUCCESS)
197                 cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
198                             "unknown class '%s'", str);
199         return (result);
200 }
201
202 dns_zonetype_t
203 ns_config_getzonetype(cfg_obj_t *zonetypeobj) {
204         dns_zonetype_t ztype = dns_zone_none;
205         char *str;
206
207         str = cfg_obj_asstring(zonetypeobj);
208         if (strcasecmp(str, "master") == 0)
209                 ztype = dns_zone_master;
210         else if (strcasecmp(str, "slave") == 0)
211                 ztype = dns_zone_slave;
212         else if (strcasecmp(str, "stub") == 0)
213                 ztype = dns_zone_stub;
214         else
215                 INSIST(0);
216         return (ztype);
217 }
218
219 isc_result_t
220 ns_config_getiplist(cfg_obj_t *config, cfg_obj_t *list,
221                     in_port_t defport, isc_mem_t *mctx,
222                     isc_sockaddr_t **addrsp, isc_uint32_t *countp)
223 {
224         int count, i = 0;
225         cfg_obj_t *addrlist;
226         cfg_obj_t *portobj;
227         cfg_listelt_t *element;
228         isc_sockaddr_t *addrs;
229         in_port_t port;
230         isc_result_t result;
231
232         INSIST(addrsp != NULL && *addrsp == NULL);
233
234         addrlist = cfg_tuple_get(list, "addresses");
235         count = ns_config_listcount(addrlist);
236
237         portobj = cfg_tuple_get(list, "port");
238         if (cfg_obj_isuint32(portobj)) {
239                 isc_uint32_t val = cfg_obj_asuint32(portobj);
240                 if (val > ISC_UINT16_MAX) {
241                         cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
242                                     "port '%u' out of range", val);
243                         return (ISC_R_RANGE);
244                 }
245                 port = (in_port_t) val;
246         } else if (defport != 0)
247                 port = defport;
248         else {
249                 result = ns_config_getport(config, &port);
250                 if (result != ISC_R_SUCCESS)
251                         return (result);
252         }
253
254         addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
255         if (addrs == NULL)
256                 return (ISC_R_NOMEMORY);
257
258         for (element = cfg_list_first(addrlist);
259              element != NULL;
260              element = cfg_list_next(element), i++)
261         {
262                 INSIST(i < count);
263                 addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element));
264                 if (isc_sockaddr_getport(&addrs[i]) == 0)
265                         isc_sockaddr_setport(&addrs[i], port);
266         }
267         INSIST(i == count);
268
269         *addrsp = addrs;
270         *countp = count;
271
272         return (ISC_R_SUCCESS);
273 }
274
275 void
276 ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
277                     isc_uint32_t count)
278 {
279         INSIST(addrsp != NULL && *addrsp != NULL);
280
281         isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
282         *addrsp = NULL;
283 }
284
285 isc_result_t
286 ns_config_getipandkeylist(cfg_obj_t *config, cfg_obj_t *list, isc_mem_t *mctx,
287                           isc_sockaddr_t **addrsp, dns_name_t ***keysp,
288                           isc_uint32_t *countp)
289 {
290         isc_uint32_t count, i = 0;
291         isc_result_t result;
292         cfg_listelt_t *element;
293         cfg_obj_t *addrlist;
294         cfg_obj_t *portobj;
295         in_port_t port;
296         dns_fixedname_t fname;
297         isc_sockaddr_t *addrs = NULL;
298         dns_name_t **keys = NULL;
299
300         INSIST(addrsp != NULL && *addrsp == NULL);
301
302         addrlist = cfg_tuple_get(list, "addresses");
303         count = ns_config_listcount(addrlist);
304
305         portobj = cfg_tuple_get(list, "port");
306         if (cfg_obj_isuint32(portobj)) {
307                 isc_uint32_t val = cfg_obj_asuint32(portobj);
308                 if (val > ISC_UINT16_MAX) {
309                         cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
310                                     "port '%u' out of range", val);
311                         return (ISC_R_RANGE);
312                 }
313                 port = (in_port_t) val;
314         } else {
315                 result = ns_config_getport(config, &port);
316                 if (result != ISC_R_SUCCESS)
317                         return (result);
318         }
319
320         result = ISC_R_NOMEMORY;
321
322         addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
323         if (addrs == NULL)
324                 goto cleanup;
325
326         keys = isc_mem_get(mctx, count * sizeof(dns_name_t *));
327         if (keys == NULL)
328                 goto cleanup;
329
330         for (element = cfg_list_first(addrlist);
331              element != NULL;
332              element = cfg_list_next(element), i++)
333         {
334                 cfg_obj_t *addr;
335                 cfg_obj_t *key;
336                 char *keystr;
337                 isc_buffer_t b;
338
339                 INSIST(i < count);
340
341                 addr = cfg_tuple_get(cfg_listelt_value(element), "sockaddr");
342                 key = cfg_tuple_get(cfg_listelt_value(element), "key");
343
344                 addrs[i] = *cfg_obj_assockaddr(addr);
345                 if (isc_sockaddr_getport(&addrs[i]) == 0)
346                         isc_sockaddr_setport(&addrs[i], port);
347
348                 keys[i] = NULL;
349                 if (!cfg_obj_isstring(key))
350                         continue;
351                 keys[i] = isc_mem_get(mctx, sizeof(dns_name_t));
352                 if (keys[i] == NULL)
353                         goto cleanup;
354                 dns_name_init(keys[i], NULL);
355                 
356                 keystr = cfg_obj_asstring(key);
357                 isc_buffer_init(&b, keystr, strlen(keystr));
358                 isc_buffer_add(&b, strlen(keystr));
359                 dns_fixedname_init(&fname);
360                 result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
361                                            dns_rootname, ISC_FALSE, NULL);
362                 if (result != ISC_R_SUCCESS)
363                         goto cleanup;
364                 result = dns_name_dup(dns_fixedname_name(&fname), mctx,
365                                       keys[i]);
366                 if (result != ISC_R_SUCCESS)
367                         goto cleanup;
368         }
369         INSIST(i == count);
370
371         *addrsp = addrs;
372         *keysp = keys;
373         *countp = count;
374
375         return (ISC_R_SUCCESS);
376
377  cleanup:
378         if (addrs != NULL)
379                 isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t));
380         if (keys != NULL) {
381                 unsigned int j;
382                 for (j = 0 ; j <= i; j++) {
383                         if (keys[j] == NULL)
384                                 continue;
385                         if (dns_name_dynamic(keys[j]))
386                                 dns_name_free(keys[j], mctx);
387                         isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
388                 }
389                 isc_mem_put(mctx, keys, count * sizeof(dns_name_t *));
390         }
391         return (result);
392 }
393
394 void
395 ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
396                           dns_name_t ***keysp, isc_uint32_t count)
397 {
398         unsigned int i;
399         dns_name_t **keys = *keysp;
400
401         INSIST(addrsp != NULL && *addrsp != NULL);
402
403         isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
404         for (i = 0; i < count; i++) {
405                 if (keys[i] == NULL)
406                         continue;
407                 if (dns_name_dynamic(keys[i]))
408                         dns_name_free(keys[i], mctx);
409                 isc_mem_put(mctx, keys[i], sizeof(dns_name_t));
410         }
411         isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *));
412         *addrsp = NULL;
413         *keysp = NULL;
414 }
415
416 isc_result_t
417 ns_config_getport(cfg_obj_t *config, in_port_t *portp) {
418         cfg_obj_t *maps[3];
419         cfg_obj_t *options = NULL;
420         cfg_obj_t *portobj = NULL;
421         isc_result_t result;
422         int i;
423
424         cfg_map_get(config, "options", &options);
425         i = 0;
426         if (options != NULL)
427                 maps[i++] = options;
428         maps[i++] = ns_g_defaults;
429         maps[i] = NULL;
430
431         result = ns_config_get(maps, "port", &portobj);
432         INSIST(result == ISC_R_SUCCESS);
433         if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
434                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
435                             "port '%u' out of range",
436                             cfg_obj_asuint32(portobj));
437                 return (ISC_R_RANGE);
438         }
439         *portp = (in_port_t)cfg_obj_asuint32(portobj);
440         return (ISC_R_SUCCESS);
441 }
442
443 isc_result_t
444 ns_config_getkeyalgorithm(const char *str, dns_name_t **name)
445 {
446         if (strcasecmp(str, "hmac-md5") == 0 ||
447             strcasecmp(str, "hmac-md5.sig-alg.reg.int") == 0 ||
448             strcasecmp(str, "hmac-md5.sig-alg.reg.int.") == 0)
449         {
450                 if (name != NULL)
451                         *name = dns_tsig_hmacmd5_name;
452                 return (ISC_R_SUCCESS);
453         }
454         return (ISC_R_NOTFOUND);
455 }