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 |
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 |
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 |
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 |
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 |
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 * |
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 |
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 |
|
|
} |