xref: /minix/external/bsd/bind/dist/lib/irs/context.c (revision 00b67f09)
1 /*	$NetBSD: context.c,v 1.5 2014/12/10 04:37:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2009, 2014  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id: context.c,v 1.3 2009/09/02 23:48:02 tbox Exp  */
20 
21 #include <config.h>
22 
23 #include <isc/app.h>
24 #include <isc/lib.h>
25 #include <isc/magic.h>
26 #include <isc/mem.h>
27 #include <isc/once.h>
28 #include <isc/socket.h>
29 #include <isc/task.h>
30 #include <isc/thread.h>
31 #include <isc/timer.h>
32 #include <isc/util.h>
33 
34 #include <dns/client.h>
35 #include <dns/lib.h>
36 
37 #include <irs/context.h>
38 #include <irs/dnsconf.h>
39 #include <irs/resconf.h>
40 
41 #define IRS_CONTEXT_MAGIC		ISC_MAGIC('I', 'R', 'S', 'c')
42 #define IRS_CONTEXT_VALID(c)		ISC_MAGIC_VALID(c, IRS_CONTEXT_MAGIC)
43 
44 #ifndef RESOLV_CONF
45 /*% location of resolve.conf */
46 #define RESOLV_CONF "/etc/resolv.conf"
47 #endif
48 
49 #ifndef DNS_CONF
50 /*% location of dns.conf */
51 #define DNS_CONF "/etc/dns.conf"
52 #endif
53 
54 #ifndef ISC_PLATFORM_USETHREADS
55 irs_context_t *irs_g_context = NULL;
56 #else
57 static isc_boolean_t thread_key_initialized = ISC_FALSE;
58 static isc_mutex_t thread_key_mutex;
59 static isc_thread_key_t irs_context_key;
60 static isc_once_t once = ISC_ONCE_INIT;
61 #endif
62 
63 
64 struct irs_context {
65 	/*
66 	 * An IRS context is a thread-specific object, and does not need to
67 	 * be locked.
68 	 */
69 	unsigned int			magic;
70 	isc_mem_t			*mctx;
71 	isc_appctx_t			*actx;
72 	isc_taskmgr_t			*taskmgr;
73 	isc_task_t			*task;
74 	isc_socketmgr_t			*socketmgr;
75 	isc_timermgr_t			*timermgr;
76 	dns_client_t			*dnsclient;
77 	irs_resconf_t			*resconf;
78 	irs_dnsconf_t			*dnsconf;
79 };
80 
81 static void
ctxs_destroy(isc_mem_t ** mctxp,isc_appctx_t ** actxp,isc_taskmgr_t ** taskmgrp,isc_socketmgr_t ** socketmgrp,isc_timermgr_t ** timermgrp)82 ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp,
83 	     isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
84 	     isc_timermgr_t **timermgrp)
85 {
86 	if (taskmgrp != NULL)
87 		isc_taskmgr_destroy(taskmgrp);
88 
89 	if (timermgrp != NULL)
90 		isc_timermgr_destroy(timermgrp);
91 
92 	if (socketmgrp != NULL)
93 		isc_socketmgr_destroy(socketmgrp);
94 
95 	if (actxp != NULL)
96 		isc_appctx_destroy(actxp);
97 
98 	if (mctxp != NULL)
99 		isc_mem_destroy(mctxp);
100 }
101 
102 static isc_result_t
ctxs_init(isc_mem_t ** mctxp,isc_appctx_t ** actxp,isc_taskmgr_t ** taskmgrp,isc_socketmgr_t ** socketmgrp,isc_timermgr_t ** timermgrp)103 ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
104 	  isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
105 	  isc_timermgr_t **timermgrp)
106 {
107 	isc_result_t result;
108 
109 	result = isc_mem_create(0, 0, mctxp);
110 	if (result != ISC_R_SUCCESS)
111 		goto fail;
112 
113 	result = isc_appctx_create(*mctxp, actxp);
114 	if (result != ISC_R_SUCCESS)
115 		goto fail;
116 
117 	result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
118 	if (result != ISC_R_SUCCESS)
119 		goto fail;
120 
121 	result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
122 	if (result != ISC_R_SUCCESS)
123 		goto fail;
124 
125 	result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
126 	if (result != ISC_R_SUCCESS)
127 		goto fail;
128 
129 	return (ISC_R_SUCCESS);
130 
131  fail:
132 	ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
133 
134 	return (result);
135 }
136 
137 #ifdef ISC_PLATFORM_USETHREADS
138 static void
free_specific_context(void * arg)139 free_specific_context(void *arg) {
140 	irs_context_t *context = arg;
141 
142 	irs_context_destroy(&context);
143 
144 	isc_thread_key_setspecific(irs_context_key, NULL);
145 }
146 
147 static void
thread_key_mutex_init(void)148 thread_key_mutex_init(void) {
149 	RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
150 }
151 
152 static isc_result_t
thread_key_init(void)153 thread_key_init(void) {
154 	isc_result_t result;
155 
156 	result = isc_once_do(&once, thread_key_mutex_init);
157 	if (result != ISC_R_SUCCESS)
158 		return (result);
159 
160 	if (!thread_key_initialized) {
161 		LOCK(&thread_key_mutex);
162 
163 		if (!thread_key_initialized &&
164 		    isc_thread_key_create(&irs_context_key,
165 					  free_specific_context) != 0) {
166 			result = ISC_R_FAILURE;
167 		} else
168 			thread_key_initialized = ISC_TRUE;
169 
170 		UNLOCK(&thread_key_mutex);
171 	}
172 
173 	return (result);
174 }
175 #endif /* ISC_PLATFORM_USETHREADS */
176 
177 isc_result_t
irs_context_get(irs_context_t ** contextp)178 irs_context_get(irs_context_t **contextp) {
179 	irs_context_t *context;
180 	isc_result_t result;
181 
182 	REQUIRE(contextp != NULL && *contextp == NULL);
183 
184 #ifndef ISC_PLATFORM_USETHREADS
185 	if (irs_g_context == NULL) {
186 		result = irs_context_create(&irs_g_context);
187 		if (result != ISC_R_SUCCESS)
188 			return (result);
189 	}
190 
191 	context = irs_g_context;
192 #else
193 	result = thread_key_init();
194 	if (result != ISC_R_SUCCESS)
195 		return (result);
196 
197 	context = isc_thread_key_getspecific(irs_context_key);
198 	if (context == NULL) {
199 		result = irs_context_create(&context);
200 		if (result != ISC_R_SUCCESS)
201 			return (result);
202 		result = isc_thread_key_setspecific(irs_context_key, context);
203 		if (result != ISC_R_SUCCESS) {
204 			irs_context_destroy(&context);
205 			return (result);
206 		}
207 	}
208 #endif /* ISC_PLATFORM_USETHREADS */
209 
210 	*contextp = context;
211 
212 	return (ISC_R_SUCCESS);
213 }
214 
215 isc_result_t
irs_context_create(irs_context_t ** contextp)216 irs_context_create(irs_context_t **contextp) {
217 	isc_result_t result;
218 	irs_context_t *context;
219 	isc_appctx_t *actx = NULL;
220 	isc_mem_t *mctx = NULL;
221 	isc_taskmgr_t *taskmgr = NULL;
222 	isc_socketmgr_t *socketmgr = NULL;
223 	isc_timermgr_t *timermgr = NULL;
224 	dns_client_t *client = NULL;
225 	isc_sockaddrlist_t *nameservers;
226 	irs_dnsconf_dnskeylist_t *trustedkeys;
227 	irs_dnsconf_dnskey_t *trustedkey;
228 
229 	isc_lib_register();
230 	result = dns_lib_init();
231 	if (result != ISC_R_SUCCESS)
232 		return (result);
233 
234 	result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
235 	if (result != ISC_R_SUCCESS)
236 		return (result);
237 
238 	result = isc_app_ctxstart(actx);
239 	if (result != ISC_R_SUCCESS) {
240 		ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
241 		return (result);
242 	}
243 
244 	context = isc_mem_get(mctx, sizeof(*context));
245 	if (context == NULL) {
246 		ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
247 		return (ISC_R_NOMEMORY);
248 	}
249 
250 	context->mctx = mctx;
251 	context->actx = actx;
252 	context->taskmgr = taskmgr;
253 	context->socketmgr = socketmgr;
254 	context->timermgr = timermgr;
255 	context->resconf = NULL;
256 	context->dnsconf = NULL;
257 	context->task = NULL;
258 	result = isc_task_create(taskmgr, 0, &context->task);
259 	if (result != ISC_R_SUCCESS)
260 		goto fail;
261 
262 	/* Create a DNS client object */
263 	result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
264 				    0, &client);
265 	if (result != ISC_R_SUCCESS)
266 		goto fail;
267 	context->dnsclient = client;
268 
269 	/* Read resolver configuration file */
270 	result = irs_resconf_load(mctx, RESOLV_CONF, &context->resconf);
271 	if (result != ISC_R_SUCCESS)
272 		goto fail;
273 	/* Set nameservers */
274 	nameservers = irs_resconf_getnameservers(context->resconf);
275 	result = dns_client_setservers(client, dns_rdataclass_in, NULL,
276 				       nameservers);
277 	if (result != ISC_R_SUCCESS)
278 		goto fail;
279 
280 	/* Read advanced DNS configuration (if any) */
281 	result = irs_dnsconf_load(mctx, DNS_CONF, &context->dnsconf);
282 	if (result != ISC_R_SUCCESS)
283 		goto fail;
284 	trustedkeys = irs_dnsconf_gettrustedkeys(context->dnsconf);
285 	for (trustedkey = ISC_LIST_HEAD(*trustedkeys);
286 	     trustedkey != NULL;
287 	     trustedkey = ISC_LIST_NEXT(trustedkey, link)) {
288 		result = dns_client_addtrustedkey(client, dns_rdataclass_in,
289 						  trustedkey->keyname,
290 						  trustedkey->keydatabuf);
291 		if (result != ISC_R_SUCCESS)
292 			goto fail;
293 	}
294 
295 	context->magic = IRS_CONTEXT_MAGIC;
296 	*contextp = context;
297 
298 	return (ISC_R_SUCCESS);
299 
300   fail:
301 	if (context->task != NULL)
302 		isc_task_detach(&context->task);
303 	if (context->resconf != NULL)
304 		irs_resconf_destroy(&context->resconf);
305 	if (context->dnsconf != NULL)
306 		irs_dnsconf_destroy(&context->dnsconf);
307 	if (client != NULL)
308 		dns_client_destroy(&client);
309 	ctxs_destroy(NULL, &actx, &taskmgr, &socketmgr, &timermgr);
310 	isc_mem_putanddetach(&mctx, context, sizeof(*context));
311 
312 	return (result);
313 }
314 
315 void
irs_context_destroy(irs_context_t ** contextp)316 irs_context_destroy(irs_context_t **contextp) {
317 	irs_context_t *context;
318 
319 	REQUIRE(contextp != NULL);
320 	context = *contextp;
321 	REQUIRE(IRS_CONTEXT_VALID(context));
322 
323 	isc_task_detach(&context->task);
324 	irs_dnsconf_destroy(&context->dnsconf);
325 	irs_resconf_destroy(&context->resconf);
326 	dns_client_destroy(&context->dnsclient);
327 
328 	ctxs_destroy(NULL, &context->actx, &context->taskmgr,
329 		     &context->socketmgr, &context->timermgr);
330 
331 	context->magic = 0;
332 
333 	isc_mem_putanddetach(&context->mctx, context, sizeof(*context));
334 
335 	*contextp = NULL;
336 
337 #ifndef ISC_PLATFORM_USETHREADS
338 	irs_g_context = NULL;
339 #else
340 	(void)isc_thread_key_setspecific(irs_context_key, NULL);
341 #endif
342 }
343 
344 isc_mem_t *
irs_context_getmctx(irs_context_t * context)345 irs_context_getmctx(irs_context_t *context) {
346 	REQUIRE(IRS_CONTEXT_VALID(context));
347 
348 	return (context->mctx);
349 }
350 
351 isc_appctx_t *
irs_context_getappctx(irs_context_t * context)352 irs_context_getappctx(irs_context_t *context) {
353 	REQUIRE(IRS_CONTEXT_VALID(context));
354 
355 	return (context->actx);
356 }
357 
358 isc_taskmgr_t *
irs_context_gettaskmgr(irs_context_t * context)359 irs_context_gettaskmgr(irs_context_t *context) {
360 	REQUIRE(IRS_CONTEXT_VALID(context));
361 
362 	return (context->taskmgr);
363 }
364 
365 isc_timermgr_t *
irs_context_gettimermgr(irs_context_t * context)366 irs_context_gettimermgr(irs_context_t *context) {
367 	REQUIRE(IRS_CONTEXT_VALID(context));
368 
369 	return (context->timermgr);
370 }
371 
372 isc_task_t *
irs_context_gettask(irs_context_t * context)373 irs_context_gettask(irs_context_t *context) {
374 	REQUIRE(IRS_CONTEXT_VALID(context));
375 
376 	return (context->task);
377 }
378 
379 dns_client_t *
irs_context_getdnsclient(irs_context_t * context)380 irs_context_getdnsclient(irs_context_t *context) {
381 	REQUIRE(IRS_CONTEXT_VALID(context));
382 
383 	return (context->dnsclient);
384 }
385 
386 irs_resconf_t *
irs_context_getresconf(irs_context_t * context)387 irs_context_getresconf(irs_context_t *context) {
388 	REQUIRE(IRS_CONTEXT_VALID(context));
389 
390 	return (context->resconf);
391 }
392 
393 irs_dnsconf_t *
irs_context_getdnsconf(irs_context_t * context)394 irs_context_getdnsconf(irs_context_t *context) {
395 	REQUIRE(IRS_CONTEXT_VALID(context));
396 
397 	return (context->dnsconf);
398 }
399