1 /* $OpenBSD: npppd_config.c,v 1.15 2024/07/11 14:05:59 yasuoka Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /* $Id: npppd_config.c,v 1.15 2024/07/11 14:05:59 yasuoka Exp $ */
29 /*@file
30 * This file provides functions which operates configuration and so on.
31 */
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <net/if_dl.h>
35 #include <netinet/ip.h>
36 #include <net/route.h>
37 #include <arpa/inet.h>
38 #include <syslog.h>
39 #include <time.h>
40 #include <event.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <stddef.h>
45 #include <errno.h>
46
47 #include "addr_range.h"
48 #include "debugutil.h"
49 #include "npppd_subr.h"
50 #include "npppd_local.h"
51 #include "npppd_auth.h"
52 #include "npppd_iface.h"
53 #include "radish.h"
54
55 #include "pathnames.h"
56
57 #ifdef NPPPD_CONFIG_DEBUG
58 #define NPPPD_CONFIG_DBG(x) log_printf x
59 #define NPPPD_CONFIG_ASSERT(x) ASSERT(x)
60 #else
61 #define NPPPD_CONFIG_DBG(x)
62 #define NPPPD_CONFIG_ASSERT(x)
63 #endif
64
65 static int npppd_pool_load(npppd *);
66 static int npppd_auth_realm_reload (npppd *);
67 static npppd_auth_base *realm_list_remove (slist *, const char *);
68
69 int
npppd_config_check(const char * path)70 npppd_config_check(const char *path)
71 {
72 struct npppd_conf conf;
73
74 npppd_conf_init(&conf);
75 return npppd_conf_parse(&conf, path);
76 }
77
78 /***********************************************************************
79 * Reading the configuration. This is the export function which
80 * aggregates functions to read from each part.
81 ***********************************************************************/
82 /**
83 * reload the configuration file.
84 * @param _this pointer indicated to npppd
85 * @returns A 0 is returned if succeeds, otherwise non 0 is returned
86 * in case of configuration error.
87 */
88 int
npppd_reload_config(npppd * _this)89 npppd_reload_config(npppd *_this)
90 {
91 int retval = -1;
92 struct npppd_conf conf;
93
94 npppd_conf_init(&conf);
95 if (npppd_conf_parse(&conf, _this->config_file) != 0) {
96 log_printf(LOG_ERR, "Load configuration from='%s' failed",
97 _this->config_file);
98 retval = -1;
99 goto fail;
100 }
101
102 _this->conf = conf;
103
104 retval = 0;
105 log_printf(LOG_NOTICE, "Load configuration from='%s' successfully.",
106 _this->config_file);
107
108 /* FALLTHROUGH */
109 fail:
110
111 return retval;
112 }
113
114 /** reload the configuration for each module */
115 int
npppd_modules_reload(npppd * _this)116 npppd_modules_reload(npppd *_this)
117 {
118 int rval;
119
120 rval = 0;
121 if (npppd_pool_load(_this) != 0)
122 return -1;
123
124 npppd_auth_realm_reload(_this);
125 #ifdef USE_NPPPD_L2TP
126 rval |= l2tpd_reload(&_this->l2tpd, &_this->conf.l2tp_confs);
127 #endif
128 #ifdef USE_NPPPD_PPTP
129 rval |= pptpd_reload(&_this->pptpd, &_this->conf.pptp_confs);
130 #endif
131 #ifdef USE_NPPPD_PPPOE
132 rval |= pppoed_reload(&_this->pppoed, &_this->conf.pppoe_confs);
133 #endif
134 #ifdef USE_NPPPD_RADIUS
135 npppd_radius_dae_init(_this);
136 #endif
137
138 return rval;
139 }
140
141 /***********************************************************************
142 * reload the configuration on each part
143 ***********************************************************************/
144 /** load the configuration for IP address pool */
145 static int
npppd_pool_load(npppd * _this)146 npppd_pool_load(npppd *_this)
147 {
148 int n, i, j;
149 npppd_pool pool0[NPPPD_MAX_IFACE];
150 struct radish_head *rd_curr, *rd_new;
151 struct ipcpconf *ipcp;
152
153 rd_curr = _this->rd;
154 rd_new = NULL;
155
156 n = 0;
157 if (!rd_inithead((void *)&rd_new, 0x41,
158 sizeof(struct sockaddr_npppd),
159 offsetof(struct sockaddr_npppd, snp_addr),
160 sizeof(struct in_addr), sockaddr_npppd_match)) {
161 goto fail;
162 }
163 _this->rd = rd_new;
164
165 TAILQ_FOREACH(ipcp, &_this->conf.ipcpconfs, entry) {
166 if (n >= countof(_this->pool)) {
167 log_printf(LOG_WARNING, "number of the pool reached "
168 "limit=%d",(int)countof(_this->pool));
169 break;
170 }
171 if (npppd_pool_init(&pool0[n], _this, ipcp->name) != 0) {
172 log_printf(LOG_WARNING, "Failed to initialize "
173 "npppd_pool '%s': %m", ipcp->name);
174 goto fail;
175 }
176 if (npppd_pool_reload(&pool0[n]) != 0)
177 goto fail;
178 n++;
179 }
180 for (; n < countof(pool0); n++)
181 pool0[n].initialized = 0;
182
183 _this->rd = rd_curr; /* backup */
184 if (npppd_set_radish(_this, rd_new) != 0)
185 goto fail;
186
187 for (i = 0; i < countof(_this->pool); i++) {
188 if (_this->pool[i].initialized != 0)
189 npppd_pool_uninit(&_this->pool[i]);
190 if (pool0[i].initialized == 0)
191 continue;
192 _this->pool[i] = pool0[i];
193 /* swap references */
194 for (j = 0; j < _this->pool[i].addrs_size; j++) {
195 if (_this->pool[i].initialized == 0)
196 continue;
197 _this->pool[i].addrs[j].snp_data_ptr = &_this->pool[i];
198 }
199 }
200 log_printf(LOG_INFO, "Loading pool config successfully.");
201
202 return 0;
203 fail:
204 /* rollback */
205 for (i = 0; i < n; i++) {
206 if (pool0[i].initialized != 0)
207 npppd_pool_uninit(&pool0[i]);
208 }
209
210 if (rd_curr != NULL)
211 _this->rd = rd_curr;
212
213 if (rd_new != NULL) {
214 rd_walktree(rd_new,
215 (int (*)(struct radish *, void *))rd_unlink,
216 rd_new->rdh_top);
217 free(rd_new);
218 }
219 log_printf(LOG_NOTICE, "Loading pool config failed");
220
221 return 1;
222 }
223
224 /* authentication realm */
225 static int
npppd_auth_realm_reload(npppd * _this)226 npppd_auth_realm_reload(npppd *_this)
227 {
228 int rval;
229 slist realms0, nrealms;
230 struct authconf *auth;
231 npppd_auth_base *auth_base;
232
233 rval = 0;
234 slist_init(&realms0);
235 slist_init(&nrealms);
236
237 if (slist_add_all(&realms0, &_this->realms) != 0) {
238 log_printf(LOG_WARNING, "slist_add_all() failed in %s(): %m",
239 __func__);
240 goto fail;
241 }
242
243 TAILQ_FOREACH(auth, &_this->conf.authconfs, entry) {
244 #ifndef USE_NPPPD_RADIUS
245 if (auth->auth_type == NPPPD_AUTH_TYPE_RADIUS) {
246 log_printf(LOG_WARNING, "radius support is not "
247 "enabled by compile time.");
248 continue;
249 }
250 #endif
251 auth_base = realm_list_remove(&realms0, auth->name);
252 if (auth_base != NULL &&
253 npppd_auth_get_type(auth_base) != auth->auth_type) {
254 /*
255 * The type of authentication has been changed in the
256 * same label name.
257 */
258 slist_add(&realms0, auth_base);
259 auth_base = NULL;
260 }
261
262 if (auth_base == NULL) {
263 /* create newly */
264 if ((auth_base = npppd_auth_create(auth->auth_type,
265 auth->name, _this)) == NULL) {
266 log_printf(LOG_WARNING, "npppd_auth_create() "
267 "failed in %s(): %m", __func__);
268 goto fail;
269 }
270 }
271 slist_add(&nrealms, auth_base);
272 }
273 if (slist_set_size(&_this->realms, slist_length(&nrealms)) != 0) {
274 log_printf(LOG_WARNING, "slist_set_size() failed in %s(): %m",
275 __func__);
276 goto fail;
277 }
278
279 slist_itr_first(&realms0);
280 while (slist_itr_has_next(&realms0)) {
281 auth_base = slist_itr_next(&realms0);
282 if (npppd_auth_is_disposing(auth_base))
283 continue;
284 npppd_auth_dispose(auth_base);
285 }
286
287 slist_itr_first(&nrealms);
288 while (slist_itr_has_next(&nrealms)) {
289 auth_base = slist_itr_next(&nrealms);
290 rval |= npppd_auth_reload(auth_base);
291 }
292 slist_remove_all(&_this->realms);
293 (void)slist_add_all(&_this->realms, &nrealms);
294 (void)slist_add_all(&_this->realms, &realms0);
295
296 slist_fini(&realms0);
297 slist_fini(&nrealms);
298
299 return rval;
300 fail:
301
302 slist_itr_first(&nrealms);
303 while (slist_itr_has_next(&nrealms)) {
304 auth_base = slist_itr_next(&nrealms);
305 npppd_auth_destroy(auth_base);
306 }
307 slist_fini(&realms0);
308 slist_fini(&nrealms);
309
310 return 1;
311 }
312
313 static npppd_auth_base *
realm_list_remove(slist * list0,const char * label)314 realm_list_remove(slist *list0, const char *label)
315 {
316 npppd_auth_base *base;
317
318 for (slist_itr_first(list0); slist_itr_has_next(list0); ) {
319 base = slist_itr_next(list0);
320 if (npppd_auth_is_disposing(base))
321 continue;
322 if (strcmp(npppd_auth_get_name(base), label) == 0)
323 return slist_itr_remove(list0);
324 }
325
326 return NULL;
327 }
328
329 /** load the interface configuration */
330 int
npppd_ifaces_load_config(npppd * _this)331 npppd_ifaces_load_config(npppd *_this)
332 {
333 int i;
334 struct iface *iface;
335 npppd_iface *niface;
336
337 for (i = 0; i < countof(_this->iface); i++) {
338 if (_this->iface[i].initialized == 0)
339 continue;
340 TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
341 if (strcmp(_this->iface[i].ifname, iface->name) == 0)
342 break;
343 }
344 if (iface == NULL) {
345 npppd_iface_stop(&_this->iface[i]);
346 npppd_iface_fini(&_this->iface[i]);
347 }
348 }
349 TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
350 /* find the existing entry or first free entry */
351 niface = NULL;
352 for (i = 0; i < countof(_this->iface); i++) {
353 if (_this->iface[i].initialized == 0) {
354 if (niface == NULL)
355 niface = &_this->iface[i];
356 continue;
357 }
358 if (strcmp(_this->iface[i].ifname, iface->name) == 0) {
359 niface = &_this->iface[i];
360 break;
361 }
362 }
363 if (niface == NULL) {
364 log_printf(LOG_WARNING,
365 "number of the interface reached limit=%d",
366 (int)countof(_this->iface));
367 break;
368 }
369 if (niface->initialized == 0)
370 npppd_iface_init(_this, niface, iface);
371 else
372 npppd_iface_reinit(niface, iface);
373 }
374
375 return 0;
376 }
377