#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if_dl.h>
#include <netinet/ip.h>
#include <net/route.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <time.h>
#include <event.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "addr_range.h"
#include "debugutil.h"
#include "npppd_subr.h"
#include "npppd_local.h"
#include "npppd_auth.h"
#include "npppd_iface.h"
#include "radish.h"
#include "pathnames.h"
#ifdef NPPPD_CONFIG_DEBUG
#define NPPPD_CONFIG_DBG(x) log_printf x
#define NPPPD_CONFIG_ASSERT(x) ASSERT(x)
#else
#define NPPPD_CONFIG_DBG(x)
#define NPPPD_CONFIG_ASSERT(x)
#endif
static int npppd_pool_load(npppd *);
static int npppd_auth_realm_reload (npppd *);
static npppd_auth_base *realm_list_remove (slist *, const char *);
int
npppd_config_check(const char *path)
{
struct npppd_conf conf;
npppd_conf_init(&conf);
return npppd_conf_parse(&conf, path);
}
int
npppd_reload_config(npppd *_this)
{
int retval = -1;
struct npppd_conf conf;
npppd_conf_init(&conf);
if (npppd_conf_parse(&conf, _this->config_file) != 0) {
log_printf(LOG_ERR, "Load configuration from='%s' failed",
_this->config_file);
retval = -1;
goto fail;
}
_this->conf = conf;
retval = 0;
log_printf(LOG_NOTICE, "Load configuration from='%s' successfully.",
_this->config_file);
fail:
return retval;
}
int
npppd_modules_reload(npppd *_this)
{
int rval;
rval = 0;
if (npppd_pool_load(_this) != 0)
return -1;
npppd_auth_realm_reload(_this);
#ifdef USE_NPPPD_L2TP
rval |= l2tpd_reload(&_this->l2tpd, &_this->conf.l2tp_confs);
#endif
#ifdef USE_NPPPD_PPTP
rval |= pptpd_reload(&_this->pptpd, &_this->conf.pptp_confs);
#endif
#ifdef USE_NPPPD_PPPOE
rval |= pppoed_reload(&_this->pppoed, &_this->conf.pppoe_confs);
#endif
#ifdef USE_NPPPD_RADIUS
npppd_radius_dae_init(_this);
#endif
return rval;
}
static int
npppd_pool_load(npppd *_this)
{
int n, i, j;
npppd_pool pool0[NPPPD_MAX_IFACE];
struct radish_head *rd_curr, *rd_new;
struct ipcpconf *ipcp;
rd_curr = _this->rd;
rd_new = NULL;
n = 0;
if (!rd_inithead((void *)&rd_new, 0x41,
sizeof(struct sockaddr_npppd),
offsetof(struct sockaddr_npppd, snp_addr),
sizeof(struct in_addr), sockaddr_npppd_match)) {
goto fail;
}
_this->rd = rd_new;
TAILQ_FOREACH(ipcp, &_this->conf.ipcpconfs, entry) {
if (n >= countof(_this->pool)) {
log_printf(LOG_WARNING, "number of the pool reached "
"limit=%d",(int)countof(_this->pool));
break;
}
if (npppd_pool_init(&pool0[n], _this, ipcp->name) != 0) {
log_printf(LOG_WARNING, "Failed to initialize "
"npppd_pool '%s': %m", ipcp->name);
goto fail;
}
if (npppd_pool_reload(&pool0[n]) != 0)
goto fail;
n++;
}
for (; n < countof(pool0); n++)
pool0[n].initialized = 0;
_this->rd = rd_curr;
if (npppd_set_radish(_this, rd_new) != 0)
goto fail;
for (i = 0; i < countof(_this->pool); i++) {
if (_this->pool[i].initialized != 0)
npppd_pool_uninit(&_this->pool[i]);
if (pool0[i].initialized == 0)
continue;
_this->pool[i] = pool0[i];
for (j = 0; j < _this->pool[i].addrs_size; j++) {
if (_this->pool[i].initialized == 0)
continue;
_this->pool[i].addrs[j].snp_data_ptr = &_this->pool[i];
}
}
log_printf(LOG_INFO, "Loading pool config successfully.");
return 0;
fail:
for (i = 0; i < n; i++) {
if (pool0[i].initialized != 0)
npppd_pool_uninit(&pool0[i]);
}
if (rd_curr != NULL)
_this->rd = rd_curr;
if (rd_new != NULL) {
rd_walktree(rd_new,
(int (*)(struct radish *, void *))rd_unlink,
rd_new->rdh_top);
free(rd_new);
}
log_printf(LOG_NOTICE, "Loading pool config failed");
return 1;
}
static int
npppd_auth_realm_reload(npppd *_this)
{
int rval;
slist realms0, nrealms;
struct authconf *auth;
npppd_auth_base *auth_base;
rval = 0;
slist_init(&realms0);
slist_init(&nrealms);
if (slist_add_all(&realms0, &_this->realms) != 0) {
log_printf(LOG_WARNING, "slist_add_all() failed in %s(): %m",
__func__);
goto fail;
}
TAILQ_FOREACH(auth, &_this->conf.authconfs, entry) {
#ifndef USE_NPPPD_RADIUS
if (auth->auth_type == NPPPD_AUTH_TYPE_RADIUS) {
log_printf(LOG_WARNING, "radius support is not "
"enabled by compile time.");
continue;
}
#endif
auth_base = realm_list_remove(&realms0, auth->name);
if (auth_base != NULL &&
npppd_auth_get_type(auth_base) != auth->auth_type) {
slist_add(&realms0, auth_base);
auth_base = NULL;
}
if (auth_base == NULL) {
if ((auth_base = npppd_auth_create(auth->auth_type,
auth->name, _this)) == NULL) {
log_printf(LOG_WARNING, "npppd_auth_create() "
"failed in %s(): %m", __func__);
goto fail;
}
}
slist_add(&nrealms, auth_base);
}
if (slist_set_size(&_this->realms, slist_length(&nrealms)) != 0) {
log_printf(LOG_WARNING, "slist_set_size() failed in %s(): %m",
__func__);
goto fail;
}
slist_itr_first(&realms0);
while (slist_itr_has_next(&realms0)) {
auth_base = slist_itr_next(&realms0);
if (npppd_auth_is_disposing(auth_base))
continue;
npppd_auth_dispose(auth_base);
}
slist_itr_first(&nrealms);
while (slist_itr_has_next(&nrealms)) {
auth_base = slist_itr_next(&nrealms);
rval |= npppd_auth_reload(auth_base);
}
slist_remove_all(&_this->realms);
(void)slist_add_all(&_this->realms, &nrealms);
(void)slist_add_all(&_this->realms, &realms0);
slist_fini(&realms0);
slist_fini(&nrealms);
return rval;
fail:
slist_itr_first(&nrealms);
while (slist_itr_has_next(&nrealms)) {
auth_base = slist_itr_next(&nrealms);
npppd_auth_destroy(auth_base);
}
slist_fini(&realms0);
slist_fini(&nrealms);
return 1;
}
static npppd_auth_base *
realm_list_remove(slist *list0, const char *label)
{
npppd_auth_base *base;
for (slist_itr_first(list0); slist_itr_has_next(list0); ) {
base = slist_itr_next(list0);
if (npppd_auth_is_disposing(base))
continue;
if (strcmp(npppd_auth_get_name(base), label) == 0)
return slist_itr_remove(list0);
}
return NULL;
}
int
npppd_ifaces_load_config(npppd *_this)
{
int i;
struct iface *iface;
npppd_iface *niface;
for (i = 0; i < countof(_this->iface); i++) {
if (_this->iface[i].initialized == 0)
continue;
TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
if (strcmp(_this->iface[i].ifname, iface->name) == 0)
break;
}
if (iface == NULL) {
npppd_iface_stop(&_this->iface[i]);
npppd_iface_fini(&_this->iface[i]);
}
}
TAILQ_FOREACH(iface, &_this->conf.ifaces, entry) {
niface = NULL;
for (i = 0; i < countof(_this->iface); i++) {
if (_this->iface[i].initialized == 0) {
if (niface == NULL)
niface = &_this->iface[i];
continue;
}
if (strcmp(_this->iface[i].ifname, iface->name) == 0) {
niface = &_this->iface[i];
break;
}
}
if (niface == NULL) {
log_printf(LOG_WARNING,
"number of the interface reached limit=%d",
(int)countof(_this->iface));
break;
}
if (niface->initialized == 0)
npppd_iface_init(_this, niface, iface);
else
npppd_iface_reinit(niface, iface);
}
return 0;
}