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