1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0 AND ISC
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*
15  * Copyright (C) Red Hat
16  *
17  * Permission to use, copy, modify, and/or distribute this software for any
18  * purpose with or without fee is hereby granted, provided that the above
19  * copyright notice and this permission notice appear in all copies.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS" AND AUTHORS DISCLAIMS ALL WARRANTIES WITH
22  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
23  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
24  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
26  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27  * PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 /*
31  * Driver API implementation and main entry point for BIND.
32  *
33  * BIND calls dyndb_version() before loading, dyndb_init() during startup
34  * and dyndb_destroy() during shutdown.
35  *
36  * It is completely up to implementation what to do.
37  *
38  * dyndb <name> <driver> {} sections in named.conf are independent so
39  * driver init() and destroy() functions are called independently for
40  * each section even if they reference the same driver/library. It is
41  * up to driver implementation to detect and catch this situation if
42  * it is undesirable.
43  */
44 
45 #include <isc/commandline.h>
46 #include <isc/hash.h>
47 #include <isc/lib.h>
48 #include <isc/mem.h>
49 #include <isc/util.h>
50 
51 #include <dns/db.h>
52 #include <dns/dyndb.h>
53 #include <dns/lib.h>
54 #include <dns/types.h>
55 
56 #include "db.h"
57 #include "instance.h"
58 #include "log.h"
59 #include "util.h"
60 
61 dns_dyndb_destroy_t dyndb_destroy;
62 dns_dyndb_register_t dyndb_init;
63 dns_dyndb_version_t dyndb_version;
64 
65 /*
66  * Driver init is called for each dyndb section in named.conf
67  * once during startup and then again on every reload.
68  *
69  * @code
70  * dyndb example-name "sample.so" { param1 param2 };
71  * @endcode
72  *
73  * @param[in] name        User-defined string from dyndb "name" {}; definition
74  *                        in named.conf.
75  *                        The example above will have name = "example-name".
76  * @param[in] parameters  User-defined parameters from dyndb section as one
77  *                        string. The example above will have
78  *                        params = "param1 param2";
79  * @param[in] file	  The name of the file from which the parameters
80  *                        were read.
81  * @param[in] line	  The line number from which the parameters were read.
82  * @param[out] instp      Pointer to instance-specific data
83  *                        (for one dyndb section).
84  */
85 isc_result_t
dyndb_init(isc_mem_t * mctx,const char * name,const char * parameters,const char * file,unsigned long line,const dns_dyndbctx_t * dctx,void ** instp)86 dyndb_init(isc_mem_t *mctx, const char *name, const char *parameters,
87 	   const char *file, unsigned long line, const dns_dyndbctx_t *dctx,
88 	   void **instp) {
89 	isc_result_t result;
90 	unsigned int argc;
91 	char **argv = NULL;
92 	char *s = NULL;
93 	sample_instance_t *sample_inst = NULL;
94 
95 	REQUIRE(name != NULL);
96 	REQUIRE(dctx != NULL);
97 
98 	/*
99 	 * Depending on how dlopen() was called, we may not have
100 	 * access to named's global namespace, in which case we need
101 	 * to initialize libisc/libdns. We check this by comparing
102 	 * the value of isc_mem_debugging to the value passed via
103 	 * the context object.
104 	 */
105 	if (dctx->memdebug != &isc_mem_debugging) {
106 		isc_lib_register();
107 		isc_log_setcontext(dctx->lctx);
108 		dns_log_setcontext(dctx->lctx);
109 		isc_hash_set_initializer(dctx->hashinit);
110 		isc_mem_debugging = *(unsigned int *)dctx->memdebug;
111 	}
112 
113 	s = isc_mem_strdup(mctx, parameters);
114 
115 	result = isc_commandline_strtoargv(mctx, s, &argc, &argv, 0);
116 	if (result != ISC_R_SUCCESS) {
117 		log_write(ISC_LOG_ERROR,
118 			  "dyndb_init: isc_commandline_strtoargv -> %s\n",
119 			  isc_result_totext(result));
120 		goto cleanup;
121 	}
122 
123 	log_write(ISC_LOG_DEBUG(9), "loading params for dyndb '%s' from %s:%lu",
124 		  name, file, line);
125 
126 	/* Finally, create the instance. */
127 	result = new_sample_instance(mctx, name, argc, argv, dctx,
128 				     &sample_inst);
129 	if (result != ISC_R_SUCCESS) {
130 		log_write(ISC_LOG_ERROR,
131 			  "dyndb_init: new_sample_instance -> %s\n",
132 			  isc_result_totext(result));
133 		goto cleanup;
134 	}
135 
136 	/*
137 	 * This is an example so we create and load zones
138 	 * right now.  This step can be arbitrarily postponed.
139 	 */
140 	result = load_sample_instance_zones(sample_inst);
141 	if (result != ISC_R_SUCCESS) {
142 		log_write(ISC_LOG_ERROR,
143 			  "dyndb_init: load_sample_instance_zones -> %s\n",
144 			  isc_result_totext(result));
145 		goto cleanup;
146 	}
147 
148 	*instp = sample_inst;
149 
150 cleanup:
151 	isc_mem_free(mctx, s);
152 	if (argv != NULL) {
153 		isc_mem_put(mctx, argv, argc * sizeof(*argv));
154 	}
155 
156 	return (result);
157 }
158 
159 /*
160  * Driver destroy is called for every instance on every reload and then once
161  * during shutdown.
162  *
163  * @param[out] instp Pointer to instance-specific data (for one dyndb section).
164  */
165 void
dyndb_destroy(void ** instp)166 dyndb_destroy(void **instp) {
167 	destroy_sample_instance((sample_instance_t **)instp);
168 }
169 
170 /*
171  * Driver version is called when loading the driver to ensure there
172  * is no API mismatch between the driver and the caller.
173  */
174 int
dyndb_version(unsigned int * flags)175 dyndb_version(unsigned int *flags) {
176 	UNUSED(flags);
177 
178 	return (DNS_DYNDB_VERSION);
179 }
180