xref: /openbsd-src/usr.sbin/npppd/npppd/npppd_config.c (revision 9791a9c53bac18b903663aae776de0cb76b3663a)
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