1    | /*
2    |  * Layer Two Tunnelling Protocol Daemon
3    |  * Copyright (C) 1998 Adtran, Inc.
4    |  *
5    |  * Mark Spencer
6    |  *
7    |  * This software is distributed under the terms
8    |  * of the GPL, which you should have received
9    |  * along with this source.
10   |  *
11   |  * File format handling
12   |  *
13   |  */
14   | 
15   | #include <stdio.h>
16   | #include <string.h>
17   | #include <unistd.h>
18   | #include <stdlib.h>
19   | #include <netdb.h>
20   | #include <netinet/in.h>
21   | 
22   | #include "l2tp.h"
23   | struct lns *lnslist;
24   | struct lac *laclist;
25   | struct lns *deflns;
26   | struct lac *deflac;
27   | struct global gconfig;
28   | char filerr[STRLEN];
29   | 
30   | int parse_config (FILE *);
31   | struct keyword words[];
32   | int init_config ()
33   | {
34   |     FILE *f;
35   |     int returnedValue;
36   | 
37   |     gconfig.port = UDP_LISTEN_PORT;
38   |     lnslist = NULL;
39   |     laclist = NULL;
40   |     deflac = (struct lac *) malloc (sizeof (struct lac));
41   |     f = fopen (CONFIG_FILE, "r");
42   |     if (f)
43   |     {
44   | 	strncpy (gconfig.authfile, DEFAULT_AUTH_FILE,
45   | 		 sizeof (gconfig.authfile));
46   |     }
47   |     else
48   |     {
49   | 	f = fopen (ALT_CONFIG_FILE, "r");
50   | 	if (f)
51   | 	{
52   | 	    strncpy (gconfig.authfile, ALT_DEFAULT_AUTH_FILE,
53   | 		     sizeof (gconfig.authfile));
54   | 	}
55   | 	else
56   | 	{
57   | 	    log (LOG_CRIT, "%s: Unable to open config file %s or %s\n",
58   | 		 __FUNCTION__, CONFIG_FILE, ALT_CONFIG_FILE);
59   | 	    return -1;
60   | 	}
61   | 
62   |     }
63   |     returnedValue = parse_config (f);
64   |     fclose (f);
65   |     return (returnedValue);
66   |     filerr[0] = 0;
67   | };
68   | 
69   | struct lns *new_lns ()
70   | {
71   |     struct lns *tmp;
72   |     tmp = (struct lns *) malloc (sizeof (struct lns));
73   |     if (!tmp)
74   |     {
75   | 	log (LOG_CRIT, "%s: Unable to allocate memory for new LNS\n",
76   | 	     __FUNCTION__);
77   | 	return NULL;
78   |     }
79   |     tmp->next = NULL;
80   |     tmp->exclusive = 0;
81   |     tmp->localaddr = 0;
82   |     tmp->tun_rws = DEFAULT_RWS_SIZE;
83   |     tmp->call_rws = DEFAULT_RWS_SIZE;
84   |     tmp->hbit = 0;
85   |     tmp->lbit = 0;
86   |     tmp->authpeer = 0;
87   |     tmp->authself = -1;
88   |     tmp->authname[0] = 0;
89   |     tmp->peername[0] = 0;
90   |     tmp->hostname[0] = 0;
91   |     tmp->entname[0] = 0;
92   |     tmp->range = NULL;
93   |     tmp->lacs = NULL;
94   |     tmp->passwdauth = 0;
95   |     tmp->pap_require = 0;
96   |     tmp->pap_refuse = 0;
97   |     tmp->chap_require = 0;
98   |     tmp->chap_refuse = 0;
99   |     tmp->idle = 0;
100  |     tmp->pridns = 0;
101  |     tmp->secdns = 0;
102  |     tmp->priwins = 0;
103  |     tmp->secwins = 0;
104  |     tmp->proxyarp = 0;
105  |     tmp->proxyauth = 0;
106  |     tmp->challenge = 0;
107  |     tmp->debug = 0;
108  |     tmp->pppoptfile[0] = 0;
109  |     tmp->t = NULL;
110  |     return tmp;
111  | }
112  | 
113  | struct lac *new_lac ()
114  | {
115  |     struct lac *tmp;
116  |     tmp = (struct lac *) malloc (sizeof (struct lac));
117  |     if (!tmp)
118  |     {
119  | 	log (LOG_CRIT, "%s: Unable to allocate memory for lac entry!\n",
120  | 	     __FUNCTION__);
121  | 	return NULL;
122  |     }
123  |     tmp->next = NULL;
124  |     tmp->rsched = NULL;
125  |     tmp->localaddr = 0;
126  |     tmp->remoteaddr = 0;
127  |     tmp->lns = 0;
128  |     tmp->tun_rws = DEFAULT_RWS_SIZE;
129  |     tmp->call_rws = DEFAULT_RWS_SIZE;
130  |     tmp->hbit = 0;
131  |     tmp->lbit = 0;
132  |     tmp->authpeer = 0;
133  |     tmp->authself = -1;
134  |     tmp->authname[0] = 0;
135  |     tmp->peername[0] = 0;
136  |     tmp->hostname[0] = 0;
137  |     tmp->entname[0] = 0;
138  |     tmp->pap_require = 0;
139  |     tmp->pap_refuse = 0;
140  |     tmp->chap_require = 0;
141  |     tmp->chap_refuse = 0;
142  |     tmp->t = NULL;
143  |     tmp->redial = 0;
144  |     tmp->rtries = 0;
145  |     tmp->rmax = 0;
146  |     tmp->challenge = 0;
147  |     tmp->autodial = 0;
148  |     tmp->rtimeout = 30;
149  |     tmp->active = 0;
150  |     tmp->debug = 0;
151  |     tmp->pppoptfile[0] = 0;
152  |     tmp->defaultroute = 0;
153  |     return tmp;
154  | }
155  | 
156  | int yesno (char *value)
157  | {
158  |     if (!strcasecmp (value, "yes") || !strcasecmp (value, "y") ||
159  | 	!strcasecmp (value, "true"))
160  | 	return 1;
161  |     else if (!strcasecmp (value, "no") || !strcasecmp (value, "n") ||
162  | 	     !strcasecmp (value, "false"))
163  | 	return 0;
164  |     else
165  | 	return -1;
166  | }
167  | 
168  | int set_boolean (char *word, char *value, int *ptr)
169  | {
170  |     int val;
171  | #ifdef DEBUG_FILE
172  |     log (LOG_DEBUG, "set_%s: %s  flag to '%s'\n", word, word, value);
173  | #endif	/* ; */
174  |     if ((val = yesno (value)) < 0)
175  |     {
176  | 	snprintf (filerr, sizeof (filerr), "%s must be 'yes' or 'no'\n",
177  | 		  word);
178  | 	return -1;
179  |     }
180  |     *ptr = val;
181  |     return 0;
182  | }
183  | 
184  | int set_int (char *word, char *value, int *ptr)
185  | {
186  |     int val;
187  | #ifdef DEBUG_FILE
188  |     log (LOG_DEBUG, "set_%s: %s  flag to '%s'\n", word, word, value);
189  | #endif	/* ; */
190  |     if ((val = atoi (value)) < 0)
191  |     {
192  | 	snprintf (filerr, sizeof (filerr), "%s must be a number\n", word);
193  | 	return -1;
194  |     }
195  |     *ptr = val;
196  |     return 0;
197  | }
198  | 
199  | int set_string (char *word, char *value, char *ptr, int len)
200  | {
201  | #ifdef DEBUG_FILE
202  |     log (LOG_DEBUG, "set_%s: %s  flag to '%s'\n", word, word, value);
203  | #endif	/* ; */
204  |     strncpy (ptr, value, len);
205  |     return 0;
206  | }
207  | 
208  | int set_port (char *word, char *value, int context, void *item)
209  | {
210  |     switch (context & ~CONTEXT_DEFAULT)
211  |     {
212  |     case CONTEXT_GLOBAL:
213  | #ifdef DEBUG_FILE
214  | 	log (LOG_DEBUG, "set_port: Setting global port number to %s\n",
215  | 	     value);
216  | #endif
217  | 	set_int (word, value, &(((struct global *) item)->port));
218  | 	break;
219  |     default:
220  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
221  | 		  word);
222  | 	return -1;
223  |     }
224  |     return 0;
225  | }
226  | 
227  | int set_rtimeout (char *word, char *value, int context, void *item)
228  | {
229  |     if (atoi (value) < 1)
230  |     {
231  | 	snprintf (filerr, sizeof (filerr),
232  | 		  "rtimeout value must be at least 1\n");
233  | 	return -1;
234  |     }
235  |     switch (context & ~CONTEXT_DEFAULT)
236  |     {
237  |     case CONTEXT_LAC:
238  | #ifdef DEBUG_FILE
239  | 	log (LOG_DEBUG, "set_rtimeout: Setting redial timeout to %s\n",
240  | 	     value);
241  | #endif
242  | 	set_int (word, value, &(((struct lac *) item)->rtimeout));
243  | 	break;
244  |     default:
245  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
246  | 		  word);
247  | 	return -1;
248  |     }
249  |     return 0;
250  | }
251  | 
252  | int set_rws (char *word, char *value, int context, void *item)
253  | {
254  |     if (atoi (value) < -1)
255  |     {
256  | 	snprintf (filerr, sizeof (filerr),
257  | 		  "receive window size must be at least -1\n");
258  | 	return -1;
259  |     }
260  |     switch (context & ~CONTEXT_DEFAULT)
261  |     {
262  |     case CONTEXT_LAC:
263  | 	if (word[0] == 'c')
264  | 	    set_int (word, value, &(((struct lac *) item)->call_rws));
265  | 	if (word[0] == 't')
266  | 	{
267  | 	    set_int (word, value, &(((struct lac *) item)->tun_rws));
268  | 	    if (((struct lac *) item)->tun_rws < 1)
269  | 	    {
270  | 		snprintf (filerr, sizeof (filerr),
271  | 			  "receive window size for tunnels must be at least 1\n");
272  | 		return -1;
273  | 	    }
274  | 	}
275  | 	break;
276  |     case CONTEXT_LNS:
277  | 	if (word[0] == 'c')
278  | 	    set_int (word, value, &(((struct lns *) item)->call_rws));
279  | 	if (word[0] == 't')
280  | 	{
281  | 	    set_int (word, value, &(((struct lns *) item)->tun_rws));
282  | 	    if (((struct lns *) item)->tun_rws < 1)
283  | 	    {
284  | 		snprintf (filerr, sizeof (filerr),
285  | 			  "receive window size for tunnels must be at least 1\n");
286  | 		return -1;
287  | 	    }
288  | 	}
289  | 	break;
290  |     default:
291  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
292  | 		  word);
293  | 	return -1;
294  |     }
295  |     return 0;
296  | }
297  | 
298  | int set_rmax (char *word, char *value, int context, void *item)
299  | {
300  |     if (atoi (value) < 1)
301  |     {
302  | 	snprintf (filerr, sizeof (filerr), "rmax value must be at least 1\n");
303  | 	return -1;
304  |     }
305  |     switch (context & ~CONTEXT_DEFAULT)
306  |     {
307  |     case CONTEXT_LAC:
308  | #ifdef DEBUG_FILE
309  | 	log (LOG_DEBUG, "set_rmax: Setting max redials to %s\n", value);
310  | #endif
311  | 	set_int (word, value, &(((struct lac *) item)->rmax));
312  | 	break;
313  |     default:
314  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
315  | 		  word);
316  | 	return -1;
317  |     }
318  |     return 0;
319  | }
320  | 
321  | int set_authfile (char *word, char *value, int context, void *item)
322  | {
323  |     if (!strlen (value))
324  |     {
325  | 	snprintf (filerr, sizeof (filerr),
326  | 		  "no filename specified for authentication\n");
327  | 	return -1;
328  |     }
329  |     switch (context & ~CONTEXT_DEFAULT)
330  |     {
331  |     case CONTEXT_GLOBAL:
332  | #ifdef DEBUG_FILE
333  | 	log (LOG_DEBUG, "set_authfile: Setting global auth file to '%s'\n",
334  | 	     value);
335  | #endif	/* ; */
336  | 	strncpy (((struct global *) item)->authfile, value,
337  | 		 sizeof (((struct global *)item)->authfile));
338  | 	break;
339  |     default:
340  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
341  | 		  word);
342  | 	return -1;
343  |     }
344  |     return 0;
345  | }
346  | 
347  | int set_autodial (char *word, char *value, int context, void *item)
348  | {
349  |     switch (context & ~CONTEXT_DEFAULT)
350  |     {
351  |     case CONTEXT_LAC:
352  | 	if (set_boolean (word, value, &(((struct lac *) item)->autodial)))
353  | 	    return -1;
354  | 	break;
355  |     default:
356  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
357  | 		  word);
358  | 	return -1;
359  |     }
360  |     return 0;
361  | }
362  | 
363  | int set_flow (char *word, char *value, int context, void *item)
364  | {
365  |     int v;
366  |     set_boolean (word, value, &v);
367  |     if (v < 0)
368  | 	return -1;
369  |     switch (context & ~CONTEXT_DEFAULT)
370  |     {
371  |     case CONTEXT_LAC:
372  | 	if (v)
373  | 	{
374  | 	    if (((struct lac *) item)->call_rws < 0)
375  | 		((struct lac *) item)->call_rws = 0;
376  | 	}
377  | 	else
378  | 	{
379  | 	    ((struct lac *) item)->call_rws = -1;
380  | 	}
381  | 	break;
382  |     case CONTEXT_LNS:
383  | 	if (v)
384  | 	{
385  | 	    if (((struct lns *) item)->call_rws < 0)
386  | 		((struct lns *) item)->call_rws = 0;
387  | 	}
388  | 	else
389  | 	{
390  | 	    ((struct lns *) item)->call_rws = -1;
391  | 	}
392  | 	break;
393  |     default:
394  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
395  | 		  word);
396  | 	return -1;
397  |     }
398  |     return 0;
399  | }
400  | 
401  | int set_defaultroute (char *word, char *value, int context, void *item)
402  | {
403  |     switch (context & ~CONTEXT_DEFAULT)
404  |     {
405  |     case CONTEXT_LAC:
406  | 	if (set_boolean (word, value, &(((struct lac *) item)->defaultroute)))
407  | 	    return -1;
408  | 	break;
409  |     default:
410  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
411  | 		  word);
412  | 	return -1;
413  |     }
414  |     return 0;
415  | }
416  | 
417  | int set_authname (char *word, char *value, int context, void *item)
418  | {
419  |     struct lac *l = (struct lac *) item;
420  |     struct lns *n = (struct lns *) item;
421  |     switch (context & ~CONTEXT_DEFAULT)
422  |     {
423  |     case CONTEXT_LNS:
424  | 	if (set_string (word, value, n->authname, sizeof (n->authname)))
425  | 	    return -1;
426  | 	break;
427  |     case CONTEXT_LAC:
428  | 	if (set_string (word, value, l->authname, sizeof (l->authname)))
429  | 	    return -1;
430  | 	break;
431  |     default:
432  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
433  | 		  word);
434  | 	return -1;
435  |     }
436  |     return 0;
437  | }
438  | 
439  | int set_hostname (char *word, char *value, int context, void *item)
440  | {
441  |     struct lac *l = (struct lac *) item;
442  |     struct lns *n = (struct lns *) item;
443  |     switch (context & ~CONTEXT_DEFAULT)
444  |     {
445  |     case CONTEXT_LNS:
446  | 	if (set_string (word, value, n->hostname, sizeof (n->hostname)))
447  | 	    return -1;
448  | 	break;
449  |     case CONTEXT_LAC:
450  | 	if (set_string (word, value, l->hostname, sizeof (l->hostname)))
451  | 	    return -1;
452  | 	break;
453  |     default:
454  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
455  | 		  word);
456  | 	return -1;
457  |     }
458  |     return 0;
459  | }
460  | 
461  | int set_passwdauth (char *word, char *value, int context, void *item)
462  | {
463  |     switch (context & ~CONTEXT_DEFAULT)
464  |     {
465  |     case CONTEXT_LNS:
466  | 	if (set_boolean (word, value, &(((struct lns *) item)->passwdauth)))
467  | 	    return -1;
468  | 	break;
469  |     default:
470  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
471  | 		  word);
472  | 	return -1;
473  |     }
474  |     return 0;
475  | }
476  | 
477  | int set_hbit (char *word, char *value, int context, void *item)
478  | {
479  |     switch (context & ~CONTEXT_DEFAULT)
480  |     {
481  |     case CONTEXT_LAC:
482  | 	if (set_boolean (word, value, &(((struct lac *) item)->hbit)))
483  | 	    return -1;
484  | 	break;
485  |     case CONTEXT_LNS:
486  | 	if (set_boolean (word, value, &(((struct lns *) item)->hbit)))
487  | 	    return -1;
488  | 	break;
489  |     default:
490  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
491  | 		  word);
492  | 	return -1;
493  |     }
494  |     return 0;
495  | }
496  | 
497  | int set_challenge (char *word, char *value, int context, void *item)
498  | {
499  |     switch (context & ~CONTEXT_DEFAULT)
500  |     {
501  |     case CONTEXT_LAC:
502  | 	if (set_boolean (word, value, &(((struct lac *) item)->challenge)))
503  | 	    return -1;
504  | 	break;
505  |     case CONTEXT_LNS:
506  | 	if (set_boolean (word, value, &(((struct lns *) item)->challenge)))
507  | 	    return -1;
508  | 	break;
509  |     default:
510  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
511  | 		  word);
512  | 	return -1;
513  |     }
514  |     return 0;
515  | }
516  | 
517  | int set_lbit (char *word, char *value, int context, void *item)
518  | {
519  |     switch (context & ~CONTEXT_DEFAULT)
520  |     {
521  |     case CONTEXT_LAC:
522  | 	if (set_boolean (word, value, &(((struct lac *) item)->lbit)))
523  | 	    return -1;
524  | 	break;
525  |     case CONTEXT_LNS:
526  | 	if (set_boolean (word, value, &(((struct lns *) item)->lbit)))
527  | 	    return -1;
528  | 	break;
529  |     default:
530  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
531  | 		  word);
532  | 	return -1;
533  |     }
534  |     return 0;
535  | }
536  | 
537  | 
538  | int set_debug (char *word, char *value, int context, void *item)
539  | {
540  |     switch (context & ~CONTEXT_DEFAULT)
541  |     {
542  |     case CONTEXT_LAC:
543  | 	if (set_boolean (word, value, &(((struct lac *) item)->debug)))
544  | 	    return -1;
545  | 	break;
546  |     case CONTEXT_LNS:
547  | 	if (set_boolean (word, value, &(((struct lns *) item)->debug)))
548  | 	    return -1;
549  | 	break;
550  |     default:
551  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
552  | 		  word);
553  | 	return -1;
554  |     }
555  |     return 0;
556  | }
557  | 
558  | int set_pppoptfile (char *word, char *value, int context, void *item)
559  | {
560  |     struct lac *l = (struct lac *) item;
561  |     struct lns *n = (struct lns *) item;
562  |     switch (context & ~CONTEXT_DEFAULT)
563  |     {
564  |     case CONTEXT_LNS:
565  | 	if (set_string (word, value, n->pppoptfile, sizeof (n->pppoptfile)))
566  | 	    return -1;
567  | 	break;
568  |     case CONTEXT_LAC:
569  | 	if (set_string (word, value, l->pppoptfile, sizeof (l->pppoptfile)))
570  | 	    return -1;
571  | 	break;
572  |     default:
573  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
574  | 		  word);
575  | 	return -1;
576  |     }
577  |     return 0;
578  | }
579  | 
580  | int set_papchap (char *word, char *value, int context, void *item)
581  | {
582  |     int result;
583  |     char *c;
584  |     struct lac *l = (struct lac *) item;
585  |     struct lns *n = (struct lns *) item;
586  |     if (set_boolean (word, value, &result))
587  | 	return -1;
588  |     c = strchr (word, ' ');
589  |     c++;
590  |     switch (context & ~CONTEXT_DEFAULT)
591  |     {
592  |     case CONTEXT_LAC:
593  | 	if (c[0] == 'p')	/* PAP */
594  | 	    if (word[2] == 'f')
595  | 		l->pap_refuse = result;
596  | 	    else
597  | 		l->pap_require = result;
598  | 	else if (c[0] == 'a')	/* Authentication */
599  | 	    if (word[2] == 'f')
600  | 		l->authself = result;
601  | 	    else
602  | 		l->authpeer = result;
603  | 	else /* CHAP */ if (word[2] == 'f')
604  | 	    l->chap_refuse = result;
605  | 	else
606  | 	    l->chap_require = result;
607  | 	break;
608  |     case CONTEXT_LNS:
609  | 	if (c[0] == 'p')	/* PAP */
610  | 	    if (word[2] == 'f')
611  | 		n->pap_refuse = result;
612  | 	    else
613  | 		n->pap_require = result;
614  | 	else if (c[0] == 'a')	/* Authentication */
615  | 	    if (word[2] == 'f')
616  | 		n->authself = !result;
617  | 	    else
618  | 		n->authpeer = result;
619  | 	else /* CHAP */ if (word[2] == 'f')
620  | 	    n->chap_refuse = result;
621  | 	else
622  | 	    n->chap_require = result;
623  | 	break;
624  |     default:
625  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
626  | 		  word);
627  | 	return -1;
628  |     }
629  |     return 0;
630  | }
631  | 
632  | int set_redial (char *word, char *value, int context, void *item)
633  | {
634  |     switch (context & ~CONTEXT_DEFAULT)
635  |     {
636  |     case CONTEXT_LAC:
637  | 	if (set_boolean (word, value, &(((struct lac *) item)->redial)))
638  | 	    return -1;
639  | 	break;
640  |     default:
641  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
642  | 		  word);
643  | 	return -1;
644  |     }
645  |     return 0;
646  | }
647  | 
648  | int set_accesscontrol (char *word, char *value, int context, void *item)
649  | {
650  |     switch (context & ~CONTEXT_DEFAULT)
651  |     {
652  |     case CONTEXT_GLOBAL:
653  | 	if (set_boolean
654  | 	    (word, value, &(((struct global *) item)->accesscontrol)))
655  | 	    return -1;
656  | 	break;
657  |     default:
658  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
659  | 		  word);
660  | 	return -1;
661  |     }
662  |     return 0;
663  | }
664  | 
665  | int set_userspace (char *word, char *value, int context, void *item)
666  | {
667  |     switch (context & ~CONTEXT_DEFAULT)
668  |     {
669  |     case CONTEXT_GLOBAL:
670  | 	if (set_boolean
671  | 	    (word, value, &(((struct global *) item)->forceuserspace)))
672  | 	    return -1;
673  | 	break;
674  |     default:
675  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
676  | 		  word);
677  | 	return -1;
678  |     }
679  |     return 0;
680  | }
681  | 
682  | struct iprange *set_range (char *word, char *value, struct iprange *in)
683  | {
684  |     char *c, *d;
685  |     struct iprange *ipr, *p;
686  |     struct hostent *hp;
687  |     c = strchr (value, '-');
688  |     if (c)
689  |     {
690  | 	d = c + 1;
691  | 	*c = 0;
692  | 	while ((c >= value) && (*c < 33))
693  | 	    *(c--) = 0;
694  | 	while (*d && (*d < 33))
695  | 	    d++;
696  |     }
697  |     if (!strlen (value) || (c && !strlen (d)))
698  |     {
699  | 	snprintf (filerr, sizeof (filerr),
700  | 		  "format is '%s <host or ip> - <host or ip>'\n", word);
701  | 	return NULL;
702  |     }
703  |     ipr = (struct iprange *) malloc (sizeof (struct iprange));
704  |     ipr->next = NULL;
705  |     hp = gethostbyname (value);
706  |     if (!hp)
707  |     {
708  | 	snprintf (filerr, sizeof (filerr), "Unknown host %s\n", value);
709  | 	free (ipr);
710  | 	return NULL;
711  |     }
712  |     bcopy (hp->h_addr, &ipr->start, sizeof (unsigned int));
713  |     if (c)
714  |     {
715  | 	hp = gethostbyname (d);
716  | 	if (!hp)
717  | 	{
718  | 	    snprintf (filerr, sizeof (filerr), "Unknown host %s\n", d);
719  | 	    free (ipr);
720  | 	    return NULL;
721  | 	}
722  | 	bcopy (hp->h_addr, &ipr->end, sizeof (unsigned int));
723  |     }
724  |     else
725  | 	ipr->end = ipr->start;
726  |     if (ntohl (ipr->start) > ntohl (ipr->end))
727  |     {
728  | 	snprintf (filerr, sizeof (filerr), "start is greater than end!\n");
729  | 	free (ipr);
730  | 	return NULL;
731  |     }
732  |     if (word[0] == 'n')
733  | 	ipr->sense = SENSE_DENY;
734  |     else
735  | 	ipr->sense = SENSE_ALLOW;
736  |     p = in;
737  |     if (p)
738  |     {
739  | 	while (p->next)
740  | 	    p = p->next;
741  | 	p->next = ipr;
742  | 	return in;
743  |     }
744  |     else
745  | 	return ipr;
746  | }
747  | 
748  | int set_iprange (char *word, char *value, int context, void *item)
749  | {
750  |     struct lns *lns = (struct lns *) item;
751  |     switch (context & ~CONTEXT_DEFAULT)
752  |     {
753  |     case CONTEXT_LNS:
754  | 	break;
755  |     default:
756  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
757  | 		  word);
758  | 	return -1;
759  |     }
760  |     lns->range = set_range (word, value, lns->range);
761  |     if (!lns->range)
762  | 	return -1;
763  | #ifdef DEBUG_FILE
764  |     log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n",
765  | 	 ntohl (ipr->start), ntohl (ipr->end), ipr->sense);
766  | #endif
767  |     return 0;
768  | }
769  | 
770  | int set_lac (char *word, char *value, int context, void *item)
771  | {
772  |     struct lns *lns = (struct lns *) item;
773  |     switch (context & ~CONTEXT_DEFAULT)
774  |     {
775  |     case CONTEXT_LNS:
776  | 	break;
777  |     default:
778  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
779  | 		  word);
780  | 	return -1;
781  |     }
782  |     lns->lacs = set_range (word, value, lns->lacs);
783  |     if (!lns->lacs)
784  | 	return -1;
785  | #ifdef DEBUG_FILE
786  |     log (LOG_DEBUG, "lac start = %x, end = %x, sense=%ud\n",
787  | 	 ntohl (ipr->start), ntohl (ipr->end), ipr->sense);
788  | #endif
789  |     return 0;
790  | }
791  | 
792  | int set_exclusive (char *word, char *value, int context, void *item)
793  | {
794  |     switch (context & ~CONTEXT_DEFAULT)
795  |     {
796  |     case CONTEXT_LNS:
797  | 	if (set_boolean (word, value, &(((struct lns *) item)->exclusive)))
798  | 	    return -1;
799  | 	break;
800  |     default:
801  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
802  | 		  word);
803  | 	return -1;
804  |     }
805  |     return 0;
806  | }
807  | 
808  | int set_ip (char *word, char *value, unsigned int *addr)
809  | {
810  |     struct hostent *hp;
811  |     hp = gethostbyname (value);
812  |     if (!hp)
813  |     {
814  | 	snprintf (filerr, sizeof (filerr), "%s: host '%s' not found\n",
815  | 		  __FUNCTION__, value);
816  | 	return -1;
817  |     }
818  |     bcopy (hp->h_addr, addr, sizeof (unsigned int));
819  |     return 0;
820  | }
821  | 
822  | int set_localaddr (char *word, char *value, int context, void *item)
823  | {
824  |     struct lac *l;
825  |     struct lns *n;
826  |     switch (context & ~CONTEXT_DEFAULT)
827  |     {
828  |     case CONTEXT_LAC:
829  | 	l = (struct lac *) item;
830  | 	return set_ip (word, value, &(l->localaddr));
831  |     case CONTEXT_LNS:
832  | 	n = (struct lns *) item;
833  | 	return set_ip (word, value, &(n->localaddr));
834  |     default:
835  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
836  | 		  word);
837  | 	return -1;
838  |     }
839  |     return 0;
840  | }
841  | 
842  | int set_remoteaddr (char *word, char *value, int context, void *item)
843  | {
844  |     struct lac *l;
845  |     switch (context & ~CONTEXT_DEFAULT)
846  |     {
847  |     case CONTEXT_LAC:
848  | 	l = (struct lac *) item;
849  | 	return set_ip (word, value, &(l->remoteaddr));
850  |     default:
851  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
852  | 		  word);
853  | 	return -1;
854  |     }
855  |     return 0;
856  | }
857  | 
858  | int set_lns (char *word, char *value, int context, void *item)
859  | {
860  |     struct hostent *hp;
861  |     struct lac *l;
862  |     struct host *ipr, *pos;
863  |     char *d;
864  |     switch (context & ~CONTEXT_DEFAULT)
865  |     {
866  |     case CONTEXT_LAC:
867  | #ifdef DEBUG_FILE
868  | 	log (LOG_DEBUG, "set_lns: setting LNS to '%s'\n", value);
869  | #endif
870  | 	l = (struct lac *) item;
871  | 	d = strchr (value, ':');
872  | 	if (d)
873  | 	{
874  | 	    d[0] = 0;
875  | 	    d++;
876  | 	}
877  | 	hp = gethostbyname (value);
878  | 	if (!hp)
879  | 	{
880  | 	    snprintf (filerr, sizeof (filerr), "no such host '%s'\n", value);
881  | 	    return -1;
882  | 	}
883  | 	ipr = malloc (sizeof (struct host));
884  | 	ipr->next = NULL;
885  | 	pos = l->lns;
886  | 	if (!pos)
887  | 	{
888  | 	    l->lns = ipr;
889  | 	}
890  | 	else
891  | 	{
892  | 	    while (pos->next)
893  | 		pos = pos->next;
894  | 	    pos->next = ipr;
895  | 	}
896  | 	strncpy (ipr->hostname, value, sizeof (ipr->hostname));
897  | 	if (d)
898  | 	    ipr->port = atoi (d);
899  | 	else
900  | 	    ipr->port = UDP_LISTEN_PORT;
901  | 	break;
902  |     default:
903  | 	snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n",
904  | 		  word);
905  | 	return -1;
906  |     }
907  |     return 0;
908  | }
909  | 
910  | int parse_config (FILE * f)
911  | {
912  |     /* Read in the configuration file handed to us */
913  |     /* FIXME: I should check for incompatible options */
914  |     int context = 0;
915  |     char buf[STRLEN];
916  |     char *s, *d, *t;
917  |     int linenum = 0;
918  |     int def = 0;
919  |     struct keyword *kw;
920  |     void *data = NULL;
921  |     struct lns *tl;
922  |     struct lac *tc;
923  |     while (!feof (f))
924  |     {
925  | 	fgets (buf, sizeof (buf), f);
926  | 	if (feof (f))
927  | 	    break;
928  | 	linenum++;
929  | 	s = buf;
930  | 	/* Strip comments */
931  | 	while (*s && *s != ';')
932  | 	    s++;
933  | 	*s = 0;
934  | 	s = buf;
935  | 	if (!strlen (buf))
936  | 	    continue;
937  | 	while ((*s < 33) && *s)
938  | 	    s++;		/* Skip over beginning white space */
939  | 	t = s + strlen (s);
940  | 	while ((t >= s) && (*t < 33))
941  | 	    *(t--) = 0;		/* Ditch trailing white space */
942  | 	if (!strlen (s))
943  | 	    continue;
944  | 	if (s[0] == '[')
945  | 	{
946  | 	    /* We've got a context description */
947  | 	    if (!(t = strchr (s, ']')))
948  | 	    {
949  | 		log (LOG_CRIT, "parse_config: line %d: No closing bracket\n",
950  | 		     linenum);
951  | 		return -1;
952  | 	    }
953  | 	    t[0] = 0;
954  | 	    s++;
955  | 	    if ((d = strchr (s, ' ')))
956  | 	    {
957  | 		/* There's a parameter */
958  | 		d[0] = 0;
959  | 		d++;
960  | 	    }
961  | 	    if (d && !strcasecmp (d, "default"))
962  | 		def = CONTEXT_DEFAULT;
963  | 	    else
964  | 		def = 0;
965  | 	    if (!strcasecmp (s, "global"))
966  | 	    {
967  | 		context = CONTEXT_GLOBAL;
968  | #ifdef DEBUG_FILE
969  | 		log (LOG_DEBUG,
970  | 		     "parse_config: global context descriptor %s\n",
971  | 		     d ? d : "");
972  | #endif
973  | 		data = &gconfig;
974  | 	    }
975  | 	    else if (!strcasecmp (s, "lns"))
976  | 	    {
977  | 		context = CONTEXT_LNS;
978  | 		if (def)
979  | 		{
980  | 		    if (!deflns)
981  | 		    {
982  | 			deflns = new_lns ();
983  | 			strncpy (deflns->entname, "default",
984  | 				 sizeof (deflns->entname));
985  | 		    }
986  | 		    data = deflns;
987  | 		    continue;
988  | 		}
989  | 		data = NULL;
990  | 		tl = lnslist;
991  | 		if (d)
992  | 		{
993  | 		    while (tl)
994  | 		    {
995  | 			if (!strcasecmp (d, tl->entname))
996  | 			    break;
997  | 			tl = tl->next;
998  | 		    }
999  | 		    if (tl)
1000 | 			data = tl;
1001 | 		}
1002 | 		if (!data)
1003 | 		{
1004 | 		    data = new_lns ();
1005 | 		    if (!data)
1006 | 			return -1;
1007 | 		    ((struct lns *) data)->next = lnslist;
1008 | 		    lnslist = (struct lns *) data;
1009 | 		}
1010 | 		if (d)
1011 | 		    strncpy (((struct lns *) data)->entname,
1012 | 			     d, sizeof (((struct lns *) data)->entname));
1013 | #ifdef DEBUG_FILE
1014 | 		log (LOG_DEBUG, "parse_config: lns context descriptor %s\n",
1015 | 		     d ? d : "");
1016 | #endif
1017 | 	    }
1018 | 	    else if (!strcasecmp (s, "lac"))
1019 | 	    {
1020 | 		context = CONTEXT_LAC;
1021 | 		if (def)
1022 | 		{
1023 | 		    if (!deflac)
1024 | 		    {
1025 | 			deflac = new_lac ();
1026 | 			strncpy (deflac->entname, "default",
1027 | 				 sizeof (deflac->entname));
1028 | 		    }
1029 | 		    data = deflac;
1030 | 		    continue;
1031 | 		}
1032 | 		data = NULL;
1033 | 		tc = laclist;
1034 | 		if (d)
1035 | 		{
1036 | 		    while (tc)
1037 | 		    {
1038 | 			if (!strcasecmp (d, tc->entname))
1039 | 			    break;
1040 | 			tc = tc->next;
1041 | 		    }
1042 | 		    if (tc)
1043 | 			data = tc;
1044 | 		}
1045 | 		if (!data)
1046 | 		{
1047 | 		    data = new_lac ();
1048 | 		    if (!data)
1049 | 			return -1;
1050 | 		    ((struct lac *) data)->next = laclist;
1051 | 		    laclist = (struct lac *) data;
1052 | 		}
1053 | 		if (d)
1054 | 		    strncpy (((struct lac *) data)->entname,
1055 | 			     d, sizeof (((struct lac *) data)->entname));
1056 | #ifdef DEBUG_FILE
1057 | 		log (LOG_DEBUG, "parse_config: lac context descriptor %s\n",
1058 | 		     d ? d : "");
1059 | #endif
1060 | 	    }
1061 | 	    else
1062 | 	    {
1063 | 		log (LOG_WARN,
1064 | 		     "parse_config: line %d: unknown context '%s'\n", linenum,
1065 | 		     s);
1066 | 		return -1;
1067 | 	    }
1068 | 	}
1069 | 	else
1070 | 	{
1071 | 	    if (!context)
1072 | 	    {
1073 | 		log (LOG_WARN,
1074 | 		     "parse_config: line %d: data '%s' occurs with no context\n",
1075 | 		     linenum, s);
1076 | 		return -1;
1077 | 	    }
1078 | 	    if (!(t = strchr (s, '=')))
1079 | 	    {
1080 | 		log (LOG_WARN, "parse_config: line %d: no '=' in data\n",
1081 | 		     linenum);
1082 | 		return -1;
1083 | 	    }
1084 | 	    d = t;
1085 | 	    d--;
1086 | 	    t++;
1087 | 	    while ((d >= s) && (*d < 33))
1088 | 		d--;
1089 | 	    d++;
1090 | 	    *d = 0;
1091 | 	    while (*t && (*t < 33))
1092 | 		t++;
1093 | #ifdef DEBUG_FILE
1094 | 	    log (LOG_DEBUG, "parse_config: field is %s, value is %s\n", s, t);
1095 | #endif
1096 | 	    /* Okay, bit twidling is done.  Let's handle this */
1097 | 	    for (kw = words; kw->keyword; kw++)
1098 | 	    {
1099 | 		if (!strcasecmp (s, kw->keyword))
1100 | 		{
1101 | 		    if (kw->handler (s, t, context | def, data))
1102 | 		    {
1103 | 			log (LOG_WARN, "parse_config: line %d: %s", linenum,
1104 | 			     filerr);
1105 | 			return -1;
1106 | 		    }
1107 | 		    break;
1108 | 		}
1109 | 	    }
1110 | 	    if (!kw->keyword)
1111 | 	    {
1112 | 		log (LOG_CRIT, "parse_config: line %d: Unknown field '%s'\n",
1113 | 		     linenum, s);
1114 | 		return -1;
1115 | 	    }
1116 | 	}
1117 |     }
1118 |     return 0;
1119 | }
1120 | 
1121 | struct keyword words[] = {
1122 |     {"port", &set_port},
1123 |     {"auth file", &set_authfile},
1124 |     {"exclusive", &set_exclusive},
1125 |     {"autodial", &set_autodial},
1126 |     {"redial", &set_redial},
1127 |     {"redial timeout", &set_rtimeout},
1128 |     {"lns", &set_lns},
1129 |     {"max redials", &set_rmax},
1130 |     {"access control", &set_accesscontrol},
1131 |     {"force userspace", &set_userspace},
1132 |     {"ip range", &set_iprange},
1133 |     {"no ip range", &set_iprange},
1134 |     {"lac", &set_lac},
1135 |     {"no lac", &set_lac},
1136 |     {"local ip", &set_localaddr},
1137 |     {"remote ip", &set_remoteaddr},
1138 |     {"defaultroute", &set_defaultroute},
1139 |     {"length bit", &set_lbit},
1140 |     {"hidden bit", &set_hbit},
1141 |     {"require pap", &set_papchap},
1142 |     {"require chap", &set_papchap},
1143 |     {"require authentication", &set_papchap},
1144 |     {"require auth", &set_papchap},
1145 |     {"refuse pap", &set_papchap},
1146 |     {"refuse chap", &set_papchap},
1147 |     {"refuse authentication", &set_papchap},
1148 |     {"refuse auth", &set_papchap},
1149 |     {"unix authentication", &set_passwdauth},
1150 |     {"unix auth", &set_passwdauth},
1151 |     {"name", &set_authname},
1152 |     {"hostname", &set_hostname},
1153 |     {"ppp debug", &set_debug},
1154 |     {"pppoptfile", &set_pppoptfile},
1155 |     {"call rws", &set_rws},
1156 |     {"tunnel rws", &set_rws},
1157 |     {"flow bit", &set_flow},
1158 |     {"challenge", &set_challenge},
1159 |     {NULL, NULL}
1160 | };