1 /* $OpenBSD: npppd_config.c,v 1.14 2015/01/19 01:48:59 deraadt 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.14 2015/01/19 01:48:59 deraadt 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
135 return rval;
136 }
137
138 /***********************************************************************
139 * reload the configuration on each part
140 ***********************************************************************/
141 /** load the configuration for IP address pool */
142 static int
npppd_pool_load(npppd * _this)143 npppd_pool_load(npppd *_this)
144 {
145 int n, i, j;
146 npppd_pool pool0[NPPPD_MAX_IFACE];
147 struct radish_head *rd_curr, *rd_new;
148 struct ipcpconf *ipcp;
149
150 rd_curr = _this->rd;
151 rd_new = NULL;
152
153 n = 0;
154 if (!rd_inithead((void *)&rd_new, 0x41,
155 sizeof(struct sockaddr_npppd),
156 offsetof(struct sockaddr_npppd, snp_addr),
157 sizeof(struct in_addr), sockaddr_npppd_match)) {
158 goto fail;
159 }
160 _this->rd = rd_new;
161
162 TAILQ_FOREACH(ipcp, &_this->conf.ipcpconfs, entry) {
163 if (n >= countof(_this->pool)) {
164 log_printf(LOG_WARNING, "number of the pool reached "
165 "limit=%d",(int)countof(_this->pool));
166 break;
167 }
168 if (npppd_pool_init(&pool0[n], _this, ipcp->name) != 0) {
169 log_printf(LOG_WARNING, "Failed to initialize "
170 "npppd_pool '%s': %m", ipcp->name);
171 goto fail;
172 }
173 if (npppd_pool_reload(&pool0[n]) != 0)
174 goto fail;
175 n++;
176 }
177 for (; n < countof(pool0); n++)
178 pool0[n].initialized = 0;
179
180 _this->rd = rd_curr; /* backup */
181 if (npppd_set_radish(_this, rd_new) != 0)
182 goto fail;
183
184 for (i = 0; i < countof(_this->pool); i++) {
185 if (_this->pool[i].initialized != 0)
186 npppd_pool_uninit(&_this->pool[i]);
187 if (pool0[i].initialized == 0)
188 continue;
189 _this->pool[i] = pool0[i];
190 /* swap references */
191 for (j = 0; j < _this->pool[i].addrs_size; j++) {
192 if (_this->pool[i].initialized == 0)
193 continue;
194 _this->pool[i].addrs[j].snp_data_ptr = &_this->pool[i];
195 }
196 }
197 log_printf(LOG_INFO, "Loading pool config successfully.");
198
199 return 0;
200 fail:
201 /* rollback */
202 for (i = 0; i < n; i++) {
203 if (pool0[i].initialized != 0)
204 npppd_pool_uninit(&pool0[i]);
205 }
206
207 if (rd_curr != NULL)
208 _this->rd = rd_curr;
209
210 if (rd_new != NULL) {
211 rd_walktree(rd_new,
212 (int (*)(struct radish *, void *))rd_unlink,
213 rd_new->rdh_top);
214 free(rd_new);
215 }
216 log_printf(LOG_NOTICE, "Loading pool config failed");
217
218 return 1;
219 }
220
221 /* authentication realm */
222 static int
npppd_auth_realm_reload(npppd * _this)223 npppd_auth_realm_reload(npppd *_this)
224 {
225 int rval;
226 slist realms0, nrealms;
227 struct authconf *auth;
228 npppd_auth_base *auth_base;
229
230 rval = 0;
231 slist_init(&realms0);
232 slist_init(&nrealms);
233
234 if (slist_add_all(&realms0, &_this->realms) != 0) {
235 log_printf(LOG_WARNING, "slist_add_all() failed in %s(): %m",
236 __func__);
237 goto fail;
238 }
239
240 TAILQ_FOREACH(auth, &_this->conf.authconfs, entry) {
241 #ifndef USE_NPPPD_RADIUS
242 if (auth->auth_type == NPPPD_AUTH_TYPE_RADIUS) {
243 log_printf(LOG_WARNING, "radius support is not "
244 "enabled by compile time.");
245 continue;
246 }
247 #endif
248 auth_base = realm_list_remove(&realms0, auth->name);
249 if (auth_base != NULL &&
250 npppd_auth_get_type(auth_base) != auth->auth_type) {
251 /*
252 * The type of authentication has been changed in the
253 * same label name.
254 */
255 slist_add(&realms0, auth_base);
256 auth_base = NULL;
257 }
258
259 if (auth_base == NULL) {
260 /* create newly */
261 if ((auth_base = npppd_auth_create(auth->auth_type,
262 auth->name, _this)) == NULL) {
263 log_printf(LOG_WARNING, "npppd_auth_create() "
264 "failed in %s(): %m", __func__);
265 goto fail;
266 }
267 }
268 slist_add(&nrealms, auth_base);
269 }
270 if (slist_set_size(&_this->realms, slist_length(&nrealms)) != 0) {
271 log_printf(LOG_WARNING, "slist_set_size() failed in %s(): %m",
272 __func__);
273 goto fail;
274 }
275
276 slist_itr_first(&realms0);
277 while (slist_itr_has_next(&realms0)) {
278 auth_base = slist_itr_next(&realms0);
279 if (npppd_auth_is_disposing(auth_base))
280 continue;
281 npppd_auth_dispose(auth_base);
282 }
283
284 slist_itr_first(&nrealms);
285 while (slist_itr_has_next(&nrealms)) {
286 auth_base = slist_itr_next(&nrealms);
287 rval |= npppd_auth_reload(auth_base);
288 }
289 slist_remove_all(&_this->realms);
290 (void)slist_add_all(&_this->realms, &nrealms);
291 (void)slist_add_all(&_this->realms, &realms0);
292
293 slist_fini(&realms0);
294 slist_fini(&nrealms);
295
296 return rval;
297 fail:
298
299 slist_itr_first(&nrealms);
300 while (slist_itr_has_next(&nrealms)) {
301 auth_base = slist_itr_next(&nrealms);
302 npppd_auth_destroy(auth_base);
303 }
304 slist_fini(&realms0);
305 slist_fini(&nrealms);
306
307 return 1;
308 }
309
310 static npppd_auth_base *
realm_list_remove(slist * list0,const char * label)311 realm_list_remove(slist *list0, const char *label)
312 {
313 npppd_auth_base *base;
314
315 for (slist_itr_first(list0); slist_itr_has_next(list0); ) {
316 base = slist_itr_next(list0);
317 if (npppd_auth_is_disposing(base))
318 continue;
319 if (strcmp(npppd_auth_get_name(base), label) == 0)
320 return slist_itr_remove(list0);
321 }
322
323 return NULL;
324 }
325
326 /** load the interface configuration */
327 int
npppd_ifaces_load_config(npppd * _this)328 npppd_ifaces_load_config(npppd *_this)
329 {
330 int i;
331 struct iface *iface;
332 npppd_iface *niface;
333
334 for (i = 0; i < countof(_this->iface); i++) {
335 if (_this->iface[i].initialized == 0)
336 continue;
337 TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
338 if (strcmp(_this->iface[i].ifname, iface->name) == 0)
339 break;
340 }
341 if (iface == NULL) {
342 npppd_iface_stop(&_this->iface[i]);
343 npppd_iface_fini(&_this->iface[i]);
344 }
345 }
346 TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
347 /* find the existing entry or first free entry */
348 niface = NULL;
349 for (i = 0; i < countof(_this->iface); i++) {
350 if (_this->iface[i].initialized == 0) {
351 if (niface == NULL)
352 niface = &_this->iface[i];
353 continue;
354 }
355 if (strcmp(_this->iface[i].ifname, iface->name) == 0) {
356 niface = &_this->iface[i];
357 break;
358 }
359 }
360 if (niface == NULL) {
361 log_printf(LOG_WARNING,
362 "number of the interface reached limit=%d",
363 (int)countof(_this->iface));
364 break;
365 }
366 if (niface->initialized == 0)
367 npppd_iface_init(_this, niface, iface);
368 else
369 npppd_iface_reinit(niface, iface);
370 }
371
372 return 0;
373 }
374