1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/BBA1.5_platform/apps/public/xl2tpd-1.1.12/file.c
2024-07-22 01:58:46 -03:00

1418 lines
37 KiB
C

/*
* Layer Two Tunnelling Protocol Daemon
* Copyright (C) 1998 Adtran, Inc.
* Copyright (C) 2002 Jeff McAdams
*
* Mark Spencer
*
* This software is distributed under the terms
* of the GPL, which you should have received
* along with this source.
*
* File format handling
*
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "l2tp.h"
struct lns *lnslist;
struct lac *laclist;
struct lns *deflns;
struct lac *deflac;
struct global gconfig;
char filerr[STRLEN];
int parse_config (FILE *);
struct keyword words[];
int init_config ()
{
FILE *f;
int returnedValue;
gconfig.port = UDP_LISTEN_PORT;
gconfig.listenaddr = htonl(INADDR_ANY); /* Default is to bind (listen) to all interfaces */
gconfig.debug_avp = 0;
gconfig.debug_network = 0;
gconfig.packet_dump = 0;
gconfig.debug_tunnel = 0;
gconfig.debug_state = 0;
lnslist = NULL;
laclist = NULL;
deflac = (struct lac *) malloc (sizeof (struct lac));
f = fopen (gconfig.configfile, "r");
if (!f)
{
f = fopen (gconfig.altconfigfile, "r");
if (f)
{
l2tp_log (LOG_WARNING, "%s: Using old style config files %s and %s\n",
__FUNCTION__, gconfig.altconfigfile, gconfig.altauthfile);
strncpy (gconfig.authfile, gconfig.altauthfile,
sizeof (gconfig.authfile));
}
else
{
l2tp_log (LOG_CRIT, "%s: Unable to open config file %s or %s\n",
__FUNCTION__, gconfig.configfile, gconfig.altconfigfile);
return -1;
}
}
returnedValue = parse_config (f);
fclose (f);
return (returnedValue);
filerr[0] = 0;
}
struct lns *new_lns ()
{
struct lns *tmp;
tmp = (struct lns *) malloc (sizeof (struct lns));
if (!tmp)
{
l2tp_log (LOG_CRIT, "%s: Unable to allocate memory for new LNS\n",
__FUNCTION__);
return NULL;
}
tmp->next = NULL;
tmp->exclusive = 0;
tmp->localaddr = 0;
tmp->tun_rws = DEFAULT_RWS_SIZE;
tmp->call_rws = DEFAULT_RWS_SIZE;
tmp->hbit = 0;
tmp->lbit = 0;
tmp->authpeer = 0;
tmp->authself = -1;
tmp->authname[0] = 0;
tmp->peername[0] = 0;
tmp->hostname[0] = 0;
tmp->entname[0] = 0;
tmp->range = NULL;
tmp->assign_ip = 1; /* default to 'yes' */
tmp->lacs = NULL;
tmp->passwdauth = 0;
tmp->pap_require = 0;
tmp->pap_refuse = 0;
tmp->chap_require = 0;
tmp->chap_refuse = 0;
tmp->idle = 0;
tmp->pridns = 0;
tmp->secdns = 0;
tmp->priwins = 0;
tmp->secwins = 0;
tmp->proxyarp = 0;
tmp->proxyauth = 0;
tmp->challenge = 0;
tmp->debug = 0;
tmp->pppoptfile[0] = 0;
tmp->t = NULL;
return tmp;
}
struct lac *new_lac ()
{
struct lac *tmp;
tmp = (struct lac *) malloc (sizeof (struct lac));
if (!tmp)
{
l2tp_log (LOG_CRIT, "%s: Unable to allocate memory for lac entry!\n",
__FUNCTION__);
return NULL;
}
tmp->next = NULL;
tmp->rsched = NULL;
tmp->localaddr = 0;
tmp->remoteaddr = 0;
tmp->lns = 0;
tmp->tun_rws = DEFAULT_RWS_SIZE;
tmp->call_rws = DEFAULT_RWS_SIZE;
tmp->hbit = 0;
tmp->lbit = 0;
tmp->authpeer = 0;
tmp->authself = -1;
tmp->authname[0] = 0;
tmp->peername[0] = 0;
tmp->hostname[0] = 0;
tmp->entname[0] = 0;
tmp->pap_require = 0;
tmp->pap_refuse = 0;
tmp->chap_require = 0;
tmp->chap_refuse = 0;
tmp->t = NULL;
tmp->redial = 0;
tmp->rtries = 0;
tmp->rmax = 0;
tmp->challenge = 0;
tmp->autodial = 0;
tmp->rtimeout = 30;
tmp->active = 0;
tmp->debug = 0;
tmp->pppoptfile[0] = 0;
tmp->defaultroute = 0;
return tmp;
}
int yesno (char *value)
{
if (!strcasecmp (value, "yes") || !strcasecmp (value, "y") ||
!strcasecmp (value, "true"))
return 1;
else if (!strcasecmp (value, "no") || !strcasecmp (value, "n") ||
!strcasecmp (value, "false"))
return 0;
else
return -1;
}
int set_boolean (char *word, char *value, int *ptr)
{
int val;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value);
#endif /* ; */
if ((val = yesno (value)) < 0)
{
snprintf (filerr, sizeof (filerr), "%s must be 'yes' or 'no'\n",
word);
return -1;
}
*ptr = val;
return 0;
}
int set_int (char *word, char *value, int *ptr)
{
int val;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value);
#endif /* ; */
if ((val = atoi (value)) < 0)
{
snprintf (filerr, sizeof (filerr), "%s must be a number\n", word);
return -1;
}
*ptr = val;
return 0;
}
int set_string (char *word, char *value, char *ptr, int len)
{
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value);
#endif /* ; */
strncpy (ptr, value, len);
return 0;
}
int set_port (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_port: Setting global port number to %s\n",
value);
#endif
set_int (word, value, &(((struct global *) item)->port));
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_rtimeout (char *word, char *value, int context, void *item)
{
if (atoi (value) < 1)
{
snprintf (filerr, sizeof (filerr),
"rtimeout value must be at least 1\n");
return -1;
}
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_rtimeout: Setting redial timeout to %s\n",
value);
#endif
set_int (word, value, &(((struct lac *) item)->rtimeout));
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_rws (char *word, char *value, int context, void *item)
{
if (atoi (value) < -1)
{
snprintf (filerr, sizeof (filerr),
"receive window size must be at least -1\n");
return -1;
}
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (word[0] == 'c')
set_int (word, value, &(((struct lac *) item)->call_rws));
if (word[0] == 't')
{
set_int (word, value, &(((struct lac *) item)->tun_rws));
if (((struct lac *) item)->tun_rws < 1)
{
snprintf (filerr, sizeof (filerr),
"receive window size for tunnels must be at least 1\n");
return -1;
}
}
break;
case CONTEXT_LNS:
if (word[0] == 'c')
set_int (word, value, &(((struct lns *) item)->call_rws));
if (word[0] == 't')
{
set_int (word, value, &(((struct lns *) item)->tun_rws));
if (((struct lns *) item)->tun_rws < 1)
{
snprintf (filerr, sizeof (filerr),
"receive window size for tunnels must be at least 1\n");
return -1;
}
}
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_rmax (char *word, char *value, int context, void *item)
{
if (atoi (value) < 1)
{
snprintf (filerr, sizeof (filerr), "rmax value must be at least 1\n");
return -1;
}
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_rmax: Setting max redials to %s\n", value);
#endif
set_int (word, value, &(((struct lac *) item)->rmax));
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_authfile (char *word, char *value, int context, void *item)
{
if (!strlen (value))
{
snprintf (filerr, sizeof (filerr),
"no filename specified for authentication\n");
return -1;
}
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_authfile: Setting global auth file to '%s'\n",
value);
#endif /* ; */
strncpy (((struct global *) item)->authfile, value,
sizeof (((struct global *)item)->authfile));
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_autodial (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->autodial)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_flow (char *word, char *value, int context, void *item)
{
int v;
set_boolean (word, value, &v);
if (v < 0)
return -1;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (v)
{
if (((struct lac *) item)->call_rws < 0)
((struct lac *) item)->call_rws = 0;
}
else
{
((struct lac *) item)->call_rws = -1;
}
break;
case CONTEXT_LNS:
if (v)
{
if (((struct lns *) item)->call_rws < 0)
((struct lns *) item)->call_rws = 0;
}
else
{
((struct lns *) item)->call_rws = -1;
}
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_defaultroute (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->defaultroute)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_authname (char *word, char *value, int context, void *item)
{
struct lac *l = (struct lac *) item;
struct lns *n = (struct lns *) item;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_string (word, value, n->authname, sizeof (n->authname)))
return -1;
break;
case CONTEXT_LAC:
if (set_string (word, value, l->authname, sizeof (l->authname)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_hostname (char *word, char *value, int context, void *item)
{
struct lac *l = (struct lac *) item;
struct lns *n = (struct lns *) item;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_string (word, value, n->hostname, sizeof (n->hostname)))
return -1;
break;
case CONTEXT_LAC:
if (set_string (word, value, l->hostname, sizeof (l->hostname)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_passwdauth (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->passwdauth)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_hbit (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->hbit)))
return -1;
break;
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->hbit)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_challenge (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->challenge)))
return -1;
break;
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->challenge)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_lbit (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->lbit)))
return -1;
break;
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->lbit)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debug (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->debug)))
return -1;
break;
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->debug)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_pppoptfile (char *word, char *value, int context, void *item)
{
struct lac *l = (struct lac *) item;
struct lns *n = (struct lns *) item;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_string (word, value, n->pppoptfile, sizeof (n->pppoptfile)))
return -1;
break;
case CONTEXT_LAC:
if (set_string (word, value, l->pppoptfile, sizeof (l->pppoptfile)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_papchap (char *word, char *value, int context, void *item)
{
int result;
char *c;
struct lac *l = (struct lac *) item;
struct lns *n = (struct lns *) item;
if (set_boolean (word, value, &result))
return -1;
c = strchr (word, ' ');
c++;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (c[0] == 'p') /* PAP */
if (word[2] == 'f')
l->pap_refuse = result;
else
l->pap_require = result;
else if (c[0] == 'a') /* Authentication */
if (word[2] == 'f')
l->authself = result;
else
l->authpeer = result;
else /* CHAP */ if (word[2] == 'f')
l->chap_refuse = result;
else
l->chap_require = result;
break;
case CONTEXT_LNS:
if (c[0] == 'p') /* PAP */
if (word[2] == 'f')
n->pap_refuse = result;
else
n->pap_require = result;
else if (c[0] == 'a') /* Authentication */
if (word[2] == 'f')
n->authself = !result;
else
n->authpeer = result;
else /* CHAP */ if (word[2] == 'f')
n->chap_refuse = result;
else
n->chap_require = result;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_redial (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
if (set_boolean (word, value, &(((struct lac *) item)->redial)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_accesscontrol (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->accesscontrol)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_userspace (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->forceuserspace)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debugavp (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->debug_avp)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debugnetwork (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->debug_network)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debugpacket (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->packet_dump)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debugtunnel (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->debug_tunnel)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_debugstate (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(((struct global *) item)->debug_state)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_assignip (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->assign_ip)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
struct iprange *set_range (char *word, char *value, struct iprange *in)
{
char *c, *d = NULL, *e = NULL;
struct iprange *ipr, *p;
struct hostent *hp;
int count = 0;
c = strchr (value, '-');
if (c)
{
d = c + 1;
*c = 0;
while ((c >= value) && (*c < 33))
*(c--) = 0;
while (*d && (*d < 33))
d++;
}
if (!strlen (value) || (c && !strlen (d)))
{
snprintf (filerr, sizeof (filerr),
"format is '%s <host or ip> - <host or ip>'\n", word);
return NULL;
}
ipr = (struct iprange *) malloc (sizeof (struct iprange));
ipr->next = NULL;
hp = gethostbyname (value);
if (!hp)
{
snprintf (filerr, sizeof (filerr), "Unknown host %s\n", value);
free (ipr);
return NULL;
}
bcopy (hp->h_addr, &ipr->start, sizeof (unsigned int));
if (c)
{
e = d;
while(*e != '\0') {
if (*e++ == '.')
count++;
}
if (count != 3) {
char ip_hi[16];
strcpy(ip_hi, value);
e = strrchr(ip_hi, '.')+1;
/* Copy the last field + null terminator */
strcpy(e, d);
d = ip_hi;
}
hp = gethostbyname (d);
if (!hp)
{
snprintf (filerr, sizeof (filerr), "Unknown host %s\n", d);
free (ipr);
return NULL;
}
bcopy (hp->h_addr, &ipr->end, sizeof (unsigned int));
}
else
ipr->end = ipr->start;
if (ntohl (ipr->start) > ntohl (ipr->end))
{
snprintf (filerr, sizeof (filerr), "start is greater than end!\n");
free (ipr);
return NULL;
}
if (word[0] == 'n')
ipr->sense = SENSE_DENY;
else
ipr->sense = SENSE_ALLOW;
p = in;
if (p)
{
while (p->next)
p = p->next;
p->next = ipr;
return in;
}
else
return ipr;
}
int set_iprange (char *word, char *value, int context, void *item)
{
struct lns *lns = (struct lns *) item;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
lns->range = set_range (word, value, lns->range);
if (!lns->range)
return -1;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n",
ntohl (lns->range->start), ntohl (lns->range->end), lns->range->sense);
#endif
return 0;
}
int set_lac (char *word, char *value, int context, void *item)
{
struct lns *lns = (struct lns *) item;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
lns->lacs = set_range (word, value, lns->lacs);
if (!lns->lacs)
return -1;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "lac start = %x, end = %x, sense=%ud\n",
ntohl (lns->lacs->start), ntohl (lns->lacs->end), lns->lacs->sense);
#endif
return 0;
}
int set_exclusive (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LNS:
if (set_boolean (word, value, &(((struct lns *) item)->exclusive)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_ip (char *word, char *value, unsigned int *addr)
{
struct hostent *hp;
hp = gethostbyname (value);
if (!hp)
{
snprintf (filerr, sizeof (filerr), "%s: host '%s' not found\n",
__FUNCTION__, value);
return -1;
}
bcopy (hp->h_addr, addr, sizeof (unsigned int));
return 0;
}
int set_listenaddr (char *word, char *value, int context, void *item)
{
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_listenaddr: Setting listen address to %s\n",
value);
#endif
if (set_ip (word, value, &(((struct global *) item)->listenaddr)))
return -1;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_localaddr (char *word, char *value, int context, void *item)
{
struct lac *l;
struct lns *n;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
l = (struct lac *) item;
return set_ip (word, value, &(l->localaddr));
case CONTEXT_LNS:
n = (struct lns *) item;
return set_ip (word, value, &(n->localaddr));
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_remoteaddr (char *word, char *value, int context, void *item)
{
struct lac *l;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
l = (struct lac *) item;
return set_ip (word, value, &(l->remoteaddr));
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_lns (char *word, char *value, int context, void *item)
{
#if 0
struct hostent *hp;
#endif
struct lac *l;
struct host *ipr, *pos;
char *d;
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_LAC:
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "set_lns: setting LNS to '%s'\n", value);
#endif
l = (struct lac *) item;
d = strchr (value, ':');
if (d)
{
d[0] = 0;
d++;
}
#if 0
// why would you want to lookup hostnames at this time?
hp = gethostbyname (value);
if (!hp)
{
snprintf (filerr, sizeof (filerr), "no such host '%s'\n", value);
return -1;
}
#endif
ipr = malloc (sizeof (struct host));
ipr->next = NULL;
pos = l->lns;
if (!pos)
{
l->lns = ipr;
}
else
{
while (pos->next)
pos = pos->next;
pos->next = ipr;
}
strncpy (ipr->hostname, value, sizeof (ipr->hostname));
if (d)
ipr->port = atoi (d);
else
ipr->port = UDP_LISTEN_PORT;
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_rand_sys ()
{
l2tp_log(LOG_WARNING, "The \"rand()\" function call is not a very good source"
"of randomness\n");
rand_source = RAND_SYS;
return 0;
}
int set_ipsec_saref (char *word, char *value, int context, void *item)
{
struct global *g = ((struct global *) item);
switch (context & ~CONTEXT_DEFAULT)
{
case CONTEXT_GLOBAL:
if (set_boolean
(word, value, &(g->ipsecsaref)))
return -1;
if(g->ipsecsaref) {
l2tp_log(LOG_WARNING, "Enabling IPsec SAref processing for L2TP transport mode SAs\n");
}
break;
default:
snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
word);
return -1;
}
return 0;
}
int set_rand_dev ()
{
rand_source = RAND_DEV;
return 0;
}
int set_rand_egd (char *value)
{
l2tp_log(LOG_WARNING, "%s: not yet implemented!\n", __FUNCTION__);
rand_source = RAND_EGD;
return -1;
}
int set_rand_source (char *word, char *value, int context, void *item)
{
time_t seconds;
/*
* We're going to go ahead and seed the rand() function with srand()
* because even if we set the randomness source to dev or egd, they
* can fall back to sys if they fail, so we want to make sure we at
* least have *some* semblance of randomness available from the
* rand() function
*/
/*
* This is a sucky random number seed...just the result from the
* time() call...but...the user requested to use the rand()
* function, which is a pretty sucky source of randomness
* regardless...at least we can get a almost sorta decent seed. If
* you have any better suggestions for creating a seed...lemme know
* :/
*/
seconds = time(NULL);
srand(seconds);
if (context != CONTEXT_GLOBAL)
{
l2tp_log(LOG_WARNING, "%s: %s not valid in context %d\n",
__FUNCTION__, word, context);
return -1;
}
/* WORKING HERE */
if (strlen(value) == 0)
{
snprintf(filerr, sizeof (filerr), "no randomness source specified\n");
return -1;
}
if (strncmp(value, "egd", 3) == 0)
{
return set_rand_egd(value);
}
else if (strncmp(value, "dev", 3) == 0)
{
return set_rand_dev();
}
else if (strncmp(value, "sys", 3) == 0)
{
return set_rand_sys();
}
else
{
l2tp_log(LOG_WARNING, "%s: %s is not a valid randomness source\n",
__FUNCTION__, value);
return -1;
}
}
int parse_config (FILE * f)
{
/* Read in the configuration file handed to us */
/* FIXME: I should check for incompatible options */
int context = 0;
char buf[STRLEN];
char *s, *d, *t;
int linenum = 0;
int def = 0;
struct keyword *kw;
void *data = NULL;
struct lns *tl;
struct lac *tc;
while (!feof (f))
{
fgets (buf, sizeof (buf), f);
if (feof (f))
break;
linenum++;
s = buf;
/* Strip comments */
while (*s && *s != ';')
s++;
*s = 0;
s = buf;
if (!strlen (buf))
continue;
while ((*s < 33) && *s)
s++; /* Skip over beginning white space */
t = s + strlen (s);
while ((t >= s) && (*t < 33))
*(t--) = 0; /* Ditch trailing white space */
if (!strlen (s))
continue;
if (s[0] == '[')
{
/* We've got a context description */
if (!(t = strchr (s, ']')))
{
l2tp_log (LOG_CRIT, "parse_config: line %d: No closing bracket\n",
linenum);
return -1;
}
t[0] = 0;
s++;
if ((d = strchr (s, ' ')))
{
/* There's a parameter */
d[0] = 0;
d++;
}
if (d && !strcasecmp (d, "default"))
def = CONTEXT_DEFAULT;
else
def = 0;
if (!strcasecmp (s, "global"))
{
context = CONTEXT_GLOBAL;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG,
"parse_config: global context descriptor %s\n",
d ? d : "");
#endif
data = &gconfig;
}
else if (!strcasecmp (s, "lns"))
{
context = CONTEXT_LNS;
if (def)
{
if (!deflns)
{
deflns = new_lns ();
strncpy (deflns->entname, "default",
sizeof (deflns->entname));
}
data = deflns;
continue;
}
data = NULL;
tl = lnslist;
if (d)
{
while (tl)
{
if (!strcasecmp (d, tl->entname))
break;
tl = tl->next;
}
if (tl)
data = tl;
}
if (!data)
{
data = new_lns ();
if (!data)
return -1;
((struct lns *) data)->next = lnslist;
lnslist = (struct lns *) data;
}
if (d)
strncpy (((struct lns *) data)->entname,
d, sizeof (((struct lns *) data)->entname));
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "parse_config: lns context descriptor %s\n",
d ? d : "");
#endif
}
else if (!strcasecmp (s, "lac"))
{
context = CONTEXT_LAC;
if (def)
{
if (!deflac)
{
deflac = new_lac ();
strncpy (deflac->entname, "default",
sizeof (deflac->entname));
}
data = deflac;
continue;
}
data = NULL;
tc = laclist;
if (d)
{
while (tc)
{
if (!strcasecmp (d, tc->entname))
break;
tc = tc->next;
}
if (tc)
data = tc;
}
if (!data)
{
data = new_lac ();
if (!data)
return -1;
((struct lac *) data)->next = laclist;
laclist = (struct lac *) data;
}
if (d)
strncpy (((struct lac *) data)->entname,
d, sizeof (((struct lac *) data)->entname));
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "parse_config: lac context descriptor %s\n",
d ? d : "");
#endif
}
else
{
l2tp_log (LOG_WARNING,
"parse_config: line %d: unknown context '%s'\n", linenum,
s);
return -1;
}
}
else
{
if (!context)
{
l2tp_log (LOG_WARNING,
"parse_config: line %d: data '%s' occurs with no context\n",
linenum, s);
return -1;
}
if (!(t = strchr (s, '=')))
{
l2tp_log (LOG_WARNING, "parse_config: line %d: no '=' in data\n",
linenum);
return -1;
}
d = t;
d--;
t++;
while ((d >= s) && (*d < 33))
d--;
d++;
*d = 0;
while (*t && (*t < 33))
t++;
#ifdef DEBUG_FILE
l2tp_log (LOG_DEBUG, "parse_config: field is %s, value is %s\n", s, t);
#endif
/* Okay, bit twidling is done. Let's handle this */
for (kw = words; kw->keyword; kw++)
{
if (!strcasecmp (s, kw->keyword))
{
if (kw->handler (s, t, context | def, data))
{
l2tp_log (LOG_WARNING, "parse_config: line %d: %s", linenum,
filerr);
return -1;
}
break;
}
}
if (!kw->keyword)
{
l2tp_log (LOG_CRIT, "parse_config: line %d: Unknown field '%s'\n",
linenum, s);
return -1;
}
}
}
return 0;
}
struct keyword words[] = {
{"listen-addr", &set_listenaddr},
{"port", &set_port},
{"rand source", &set_rand_source},
{"auth file", &set_authfile},
{"exclusive", &set_exclusive},
{"autodial", &set_autodial},
{"redial", &set_redial},
{"redial timeout", &set_rtimeout},
{"lns", &set_lns},
{"max redials", &set_rmax},
{"access control", &set_accesscontrol},
{"force userspace", &set_userspace},
{"ip range", &set_iprange},
{"no ip range", &set_iprange},
{"debug avp", &set_debugavp},
{"debug network", &set_debugnetwork},
{"debug packet", &set_debugpacket},
{"debug tunnel", &set_debugtunnel},
{"debug state", &set_debugstate},
{"ipsec saref", &set_ipsec_saref},
{"lac", &set_lac},
{"no lac", &set_lac},
{"assign ip", &set_assignip},
{"local ip", &set_localaddr},
{"remote ip", &set_remoteaddr},
{"defaultroute", &set_defaultroute},
{"length bit", &set_lbit},
{"hidden bit", &set_hbit},
{"require pap", &set_papchap},
{"require chap", &set_papchap},
{"require authentication", &set_papchap},
{"require auth", &set_papchap},
{"refuse pap", &set_papchap},
{"refuse chap", &set_papchap},
{"refuse authentication", &set_papchap},
{"refuse auth", &set_papchap},
{"unix authentication", &set_passwdauth},
{"unix auth", &set_passwdauth},
{"name", &set_authname},
{"hostname", &set_hostname},
{"ppp debug", &set_debug},
{"pppoptfile", &set_pppoptfile},
{"call rws", &set_rws},
{"tunnel rws", &set_rws},
{"flow bit", &set_flow},
{"challenge", &set_challenge},
{NULL, NULL}
};