1 /* $MirOS: src/usr.sbin/isdn/isdnd/rc_config.c,v 1.2 2005/03/13 19:17:03 tg Exp $ */
2 
3 /*
4  * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *---------------------------------------------------------------------------
28  *
29  *	i4b daemon - config file processing
30  *	-----------------------------------
31  *
32  *	$Id: rc_config.c,v 1.22 2004/05/06 21:13:28 martin Exp $
33  *
34  * $FreeBSD$
35  *
36  *      last edit-date: [Sat Jan  6 12:57:36 2001]
37  *
38  *---------------------------------------------------------------------------*/
39 
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 
45 #ifdef __OpenBSD__
46 #include <sys/timeout.h>
47 #else
48 #include <sys/callout.h>
49 #endif
50 #include <sys/ioctl.h>
51 #include <ifaddrs.h>
52 
53 #include "isdnd.h"
54 #include "rc_parse.h"
55 
56 #include "monitor.h"
57 
58 __RCSID("$MirOS: src/usr.sbin/isdn/isdnd/rc_config.c,v 1.2 2005/03/13 19:17:03 tg Exp $");
59 
60 extern int lineno;
61 extern char *yytext;
62 
63 extern FILE *yyin;
64 extern int yyparse(void);
65 
66 static void set_config_defaults(void);
67 static void check_config(void);
68 static void print_config(void);
69 static void parse_valid(char *dt);
70 static int lookup_l4_driver(const char *name);
71 void init_currrent_cfg_state(void);
72 #ifdef SPPPGETAUTHCFG
73 static void set_isppp_auth(struct cfg_entry*);
74 #endif
75 static void set_autoupdown(struct cfg_entry*);
76 void flush_config(void);
77 
78 static int nregexpr = 0;
79 static int nregprog = 0;
80 static struct cfg_entry * current_cfe = NULL;
81 struct isdn_ctrl_state * cur_ctrl = NULL;
82 
83 /*---------------------------------------------------------------------------*
84  *	called from main to read and process config file
85  *---------------------------------------------------------------------------*/
86 void
configure(char * filename,int reread)87 configure(char *filename, int reread)
88 {
89 	extern void reset_scanner(FILE *inputfile);
90 
91 	set_config_defaults();
92 
93 	yyin = fopen(filename, "r");
94 
95 	if (reread)
96 	{
97 		reset_scanner(yyin);
98 		current_cfe = NULL;
99 	}
100 
101 	if (yyin == NULL)
102 	{
103 		logit(LL_ERR, "cannot fopen file [%s]", filename);
104 		exit(1);
105 	}
106 
107 	yyparse();
108 
109 	monitor_fixup_rights();
110 
111 	check_config();		/* validation and consistency check */
112 
113 	fclose(yyin);
114 
115 	if (do_print)
116 	{
117 		if (config_error_flag)
118 		{
119 			logit(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
120 			exit(1);
121 		}
122 		print_config();
123 		do_exit(0);
124 	}
125 }
126 
127 /*---------------------------------------------------------------------------*
128  *	yacc error routine
129  *---------------------------------------------------------------------------*/
130 void
yyerror(const char * msg)131 yyerror(const char *msg)
132 {
133 	logit(LL_ERR, "configuration error: %s at line %d, token \"%s\"", msg, lineno+1, yytext);
134 	config_error_flag++;
135 }
136 
137 /*
138  * Prepare a new default entry
139  */
140 void
init_currrent_cfg_state()141 init_currrent_cfg_state()
142 {
143 	if (current_cfe != NULL) {
144 		add_cfg_entry(current_cfe);
145 	}
146 	current_cfe = malloc(sizeof(struct cfg_entry));
147 	memset(current_cfe, 0, sizeof(struct cfg_entry));
148 
149 	current_cfe->isdncontroller = INVALID;
150 	current_cfe->isdnchannel = CHAN_ANY;
151 	current_cfe->usrdevice = INVALID;
152 	current_cfe->usrdeviceunit = INVALID;
153 	current_cfe->remote_numbers_handling = RNH_LAST;
154 	current_cfe->dialin_reaction = REACT_IGNORE;
155 	current_cfe->b1protocol = BPROT_NONE;
156 	current_cfe->unitlength = UNITLENGTH_DEFAULT;
157 	current_cfe->earlyhangup = EARLYHANGUP_DEFAULT;
158 	current_cfe->ratetype = INVALID_RATE;
159 	current_cfe->unitlengthsrc = ULSRC_NONE;
160 	current_cfe->answerprog = ANSWERPROG_DEF;
161 	current_cfe->callbackwait = CALLBACKWAIT_MIN;
162 	current_cfe->calledbackwait = CALLEDBACKWAIT_MIN;
163 	current_cfe->dialretries = DIALRETRIES_DEF;
164 	current_cfe->recoverytime = RECOVERYTIME_MIN;
165 	current_cfe->dialouttype = DIALOUT_NORMAL;
166 	current_cfe->inout = DIR_INOUT;
167 	current_cfe->ppp_expect_auth = AUTH_UNDEF;
168 	current_cfe->ppp_send_auth = AUTH_UNDEF;
169 	current_cfe->ppp_auth_flags = AUTH_RECHALLENGE | AUTH_REQUIRED;
170 	current_cfe->cdid = CDID_UNUSED;
171 	current_cfe->state = ST_IDLE;
172 	current_cfe->aoc_valid = AOC_INVALID;
173 	current_cfe->autoupdown = AUTOUPDOWN_YES;
174 }
175 
176 /*---------------------------------------------------------------------------*
177  *	fill all config entries with default values
178  *---------------------------------------------------------------------------*/
179 static void
set_config_defaults(void)180 set_config_defaults(void)
181 {
182 	int i;
183 
184 	/* system section cleanup */
185 
186 	nregprog = nregexpr = 0;
187 
188 	rt_prio = RTPRIO_NOTUSED;
189 
190 	mailer[0] = '\0';
191 	mailto[0] = '\0';
192 
193 	/* clean regular expression table */
194 
195 	for (i=0; i < MAX_RE; i++)
196 	{
197 		if (rarr[i].re_expr)
198 			free(rarr[i].re_expr);
199 		rarr[i].re_expr = NULL;
200 
201 		if (rarr[i].re_prog)
202 			free(rarr[i].re_prog);
203 		rarr[i].re_prog = NULL;
204 
205 		rarr[i].re_flg = 0;
206 	}
207 
208 	strlcpy(rotatesuffix, "", sizeof(rotatesuffix));
209 }
210 
211 static void
set_autoupdown(struct cfg_entry * cep)212 set_autoupdown(struct cfg_entry *cep)
213 {
214         struct ifaddrs *res = NULL, *p;
215 	struct ifreq ifr;
216 	int r, s, cnt, in6;
217 
218 	s = socket(AF_INET, SOCK_DGRAM, 0);
219 	memset(&ifr, 0, sizeof ifr);
220 	snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s%d", cep->usrdevicename, cep->usrdeviceunit);
221 	r = ioctl(s, SIOCGIFFLAGS, &ifr);
222 
223 	/*
224 	 * See if this interface has got any valid addresses - if not,
225 	 * leave it alone.
226 	 */
227 	if (r >= 0 && !(ifr.ifr_flags & IFF_UP)) {
228 		cnt = in6 = 0;
229 		if (getifaddrs(&res) == 0) {
230 			for (p = res; p; p = p->ifa_next) {
231 				if (p->ifa_addr == NULL)
232 					continue;
233 				if (p->ifa_addr->sa_family == AF_LINK)
234 					continue;
235 				if (strcmp(p->ifa_name, ifr.ifr_name) != 0)
236 					continue;
237 				if (p->ifa_addr->sa_family == AF_INET6)
238 					in6 = 1;
239 				cnt++;
240 			}
241 			freeifaddrs(res);
242 		}
243 
244 		if (in6)
245 			cnt--;	/* XXX - heuristic to adjust for INET6 local scope */
246 
247 		/* Ok, we have some addres - so UP the interface */
248 		if (cnt > 0) {
249 			ifr.ifr_flags |= IFF_UP;
250 			r = ioctl(s, SIOCSIFFLAGS, &ifr);
251 			if (r >= 0)
252 				cep->autoupdown |= AUTOUPDOWN_DONE;
253 		}
254 	}
255 
256 	close(s);
257 }
258 
259 #ifdef SPPPGETAUTHCFG
260 static void
set_isppp_auth(struct cfg_entry * cep)261 set_isppp_auth(struct cfg_entry *cep)
262 {
263 	struct spppauthcfg spcfg;
264 	int s;
265 	int doioctl = 0;
266 
267 	if (cep->ppp_expect_auth == AUTH_UNDEF
268 	   && cep->ppp_send_auth == AUTH_UNDEF)
269 		return;
270 
271 	if (cep->ppp_expect_auth == AUTH_NONE
272 	   || cep->ppp_send_auth == AUTH_NONE)
273 		doioctl = 1;
274 
275 	if ((cep->ppp_expect_auth == AUTH_CHAP
276 	     || cep->ppp_expect_auth == AUTH_PAP)
277 	    && cep->ppp_expect_name != NULL
278 	    && cep->ppp_expect_password != NULL)
279 		doioctl = 1;
280 
281 	if ((cep->ppp_send_auth == AUTH_CHAP || cep->ppp_send_auth == AUTH_PAP)
282 			&& cep->ppp_send_name != NULL
283 			&& cep->ppp_send_password != NULL)
284 		doioctl = 1;
285 
286 	if (!doioctl)
287 		return;
288 
289 	memset(&spcfg, 0, sizeof spcfg);
290 	snprintf(spcfg.ifname, sizeof(spcfg.ifname), "%s%d",
291 		cep->usrdevicename, cep->usrdeviceunit);
292 
293 	/* use a random AF to create the socket */
294 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
295 		logit(LL_ERR, "ERROR opening control socket at line %d!", lineno);
296 		config_error_flag++;
297 		return;
298 	}
299 
300 	if (ioctl(s, SPPPGETAUTHCFG, &spcfg) == -1) {
301 		logit(LL_ERR, "ERROR fetching active PPP authentication info for %s at line %d!", spcfg.ifname, lineno);
302 		close(s);
303 		config_error_flag++;
304 		return;
305 	}
306 	if (cep->ppp_expect_auth != AUTH_UNDEF)
307 	{
308 		if (cep->ppp_expect_auth == AUTH_NONE)
309 		{
310 			spcfg.hisauth = SPPP_AUTHPROTO_NONE;
311 		}
312 		else if ((cep->ppp_expect_auth == AUTH_CHAP
313 			  || cep->ppp_expect_auth == AUTH_PAP)
314 			 && cep->ppp_expect_name != NULL
315 			 && cep->ppp_expect_password != NULL)
316 		{
317 			spcfg.hisauth = cep->ppp_expect_auth == AUTH_PAP ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
318 			spcfg.hisname = cep->ppp_expect_name;
319 			spcfg.hisname_length = strlen(cep->ppp_expect_name)+1;
320 			spcfg.hissecret = cep->ppp_expect_password;
321 			spcfg.hissecret_length = strlen(cep->ppp_expect_password)+1;
322 		}
323 	}
324 	if (cep->ppp_send_auth != AUTH_UNDEF)
325 	{
326 		if (cep->ppp_send_auth == AUTH_NONE)
327 		{
328 			spcfg.myauth = SPPP_AUTHPROTO_NONE;
329 		}
330 		else if ((cep->ppp_send_auth == AUTH_CHAP
331 			  || cep->ppp_send_auth == AUTH_PAP)
332 			 && cep->ppp_send_name != NULL
333 			 && cep->ppp_send_password != NULL)
334 		{
335 			spcfg.myauth = cep->ppp_send_auth == AUTH_PAP ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
336 			spcfg.myname = cep->ppp_send_name;
337 			spcfg.myname_length = strlen(cep->ppp_send_name)+1;
338 			spcfg.mysecret = cep->ppp_send_password;
339 			spcfg.mysecret_length = strlen(cep->ppp_send_password)+1;
340 
341 			if (cep->ppp_auth_flags & AUTH_REQUIRED)
342 				spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT;
343 			else
344 				spcfg.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT;
345 
346 			if (cep->ppp_auth_flags & AUTH_RECHALLENGE)
347 				spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE;
348 			else
349 				spcfg.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE;
350 		}
351 	}
352 
353 	if (ioctl(s, SPPPSETAUTHCFG, &spcfg) == -1) {
354 		logit(LL_ERR, "ERROR setting new PPP authentication parameters for %s at line %d!", spcfg.ifname, lineno);
355 		config_error_flag++;
356 	}
357 	close(s);
358 }
359 #endif
360 
361 /*---------------------------------------------------------------------------*
362  *	extract values from config and fill table
363  *---------------------------------------------------------------------------*/
364 void
cfg_setval(int keyword)365 cfg_setval(int keyword)
366 {
367 	int i;
368 
369 	switch (keyword)
370 	{
371 	case ACCTALL:
372 		acct_all = yylval.booln;
373 		DBGL(DL_RCCF, (logit(LL_DBG, "system: acctall = %d", yylval.booln)));
374 		break;
375 
376 	case ACCTFILE:
377 		strlcpy(acctfile, yylval.str, sizeof(acctfile));
378 		DBGL(DL_RCCF, (logit(LL_DBG, "system: acctfile = %s", yylval.str)));
379 		break;
380 
381 	case ALERT:
382 		if (yylval.num < MINALERT)
383 		{
384 			yylval.num = MINALERT;
385 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert < %d, min = %d", current_cfe->name, MINALERT, yylval.num)));
386 		}
387 		else if (yylval.num > MAXALERT)
388 		{
389 			yylval.num = MAXALERT;
390 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert > %d, min = %d", current_cfe->name, MAXALERT, yylval.num)));
391 		}
392 
393 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert = %d", current_cfe->name, yylval.num)));
394 		current_cfe->alert = yylval.num;
395 		break;
396 
397 	case ALIASING:
398 		DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasing = %d", yylval.booln)));
399 		aliasing = yylval.booln;
400 		break;
401 
402 	case ALIASFNAME:
403 		strlcpy(aliasfile, yylval.str, sizeof(aliasfile));
404 		DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasfile = %s", yylval.str)));
405 		break;
406 
407 	case ANSWERPROG:
408 		if ((current_cfe->answerprog = strdup(yylval.str)) == NULL)
409 		{
410 			logit(LL_ERR, "entry %s: answerstring, malloc failed!", current_cfe->name);
411 			do_exit(1);
412 		}
413 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: answerprog = %s", current_cfe->name, yylval.str)));
414 		break;
415 
416 	case B1PROTOCOL:
417 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: b1protocol = %s", current_cfe->name, yylval.str)));
418 		if (!(strcmp(yylval.str, "raw")))
419 			current_cfe->b1protocol = BPROT_NONE;
420 		else if (!(strcmp(yylval.str, "hdlc")))
421 			current_cfe->b1protocol = BPROT_RHDLC;
422 		else
423 		{
424 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"b1protocol\" at line %d!", lineno);
425 			config_error_flag++;
426 		}
427 		break;
428 
429 	case BEEPCONNECT:
430 		do_bell = yylval.booln;
431 		DBGL(DL_RCCF, (logit(LL_DBG, "system: beepconnect = %d", yylval.booln)));
432 		break;
433 
434 	case BUDGETCALLBACKPERIOD:
435 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbackperiod = %d", current_cfe->name, yylval.num)));
436 		current_cfe->budget_callbackperiod = yylval.num;
437 		break;
438 
439 	case BUDGETCALLBACKNCALLS:
440 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbackncalls = %d", current_cfe->name, yylval.num)));
441 		current_cfe->budget_callbackncalls = yylval.num;
442 		break;
443 
444 	case BUDGETCALLOUTPERIOD:
445 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutperiod = %d", current_cfe->name, yylval.num)));
446 		current_cfe->budget_calloutperiod = yylval.num;
447 		break;
448 
449 	case BUDGETCALLOUTNCALLS:
450 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutncalls = %d", current_cfe->name, yylval.num)));
451 		current_cfe->budget_calloutncalls = yylval.num;
452 		break;
453 
454 	case AUTOUPDOWN:
455 		current_cfe->autoupdown = yylval.booln;
456 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: autoupdown = %d", current_cfe->name, yylval.booln)));
457 		break;
458 
459 	case BUDGETCALLBACKSFILEROTATE:
460 		current_cfe->budget_callbacksfile_rotate = yylval.booln;
461 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbacksfile-rotate = %d", current_cfe->name, yylval.booln)));
462 		break;
463 
464 	case BUDGETCALLBACKSFILE:
465 		{
466 			FILE *fp;
467 			int s, l;
468 			int n;
469 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbacksfile = %s", yylval.str)));
470 			fp = fopen(yylval.str, "r");
471 			if (fp != NULL)
472 			{
473 				if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
474 				{
475 					DBGL(DL_RCCF, (logit(LL_DBG, "entry %d: initializing budget-callbacksfile %s", current_cfe->name, yylval.str)));
476 					fclose(fp);
477 					fp = fopen(yylval.str, "w");
478 					if (fp != NULL)
479 						fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
480 					fclose(fp);
481 				}
482 			}
483 			else
484 			{
485 				DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: creating budget-callbacksfile %s", current_cfe->name, yylval.str)));
486 				fp = fopen(yylval.str, "w");
487 				if (fp != NULL)
488 					fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
489 				fclose(fp);
490 			}
491 
492 			fp = fopen(yylval.str, "r");
493 			if (fp != NULL)
494 			{
495 				if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
496 				{
497 					if ((current_cfe->budget_callbacks_file = strdup(yylval.str)) == NULL)
498 					{
499 						logit(LL_ERR, "entry %s: budget-callbacksfile, malloc failed!", current_cfe->name);
500 						do_exit(1);
501 					}
502 					DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using callbacksfile %s", current_cfe->name, yylval.str)));
503 				}
504 				fclose(fp);
505 			}
506 		}
507 		break;
508 
509 	case BUDGETCALLOUTSFILEROTATE:
510 		current_cfe->budget_calloutsfile_rotate = yylval.booln;
511 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutsfile-rotate = %d", current_cfe->name, yylval.booln)));
512 		break;
513 
514 	case BUDGETCALLOUTSFILE:
515 		{
516 			FILE *fp;
517 			int s, l;
518 			int n;
519 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutsfile = %s", current_cfe->name, yylval.str)));
520 			fp = fopen(yylval.str, "r");
521 			if (fp != NULL)
522 			{
523 				if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
524 				{
525 					DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: initializing budget-calloutsfile %s", current_cfe->name, yylval.str)));
526 					fclose(fp);
527 					fp = fopen(yylval.str, "w");
528 					if (fp != NULL)
529 						fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
530 					fclose(fp);
531 				}
532 			}
533 			else
534 			{
535 				DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: creating budget-calloutsfile %s", current_cfe->name, yylval.str)));
536 				fp = fopen(yylval.str, "w");
537 				if (fp != NULL)
538 					fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
539 				fclose(fp);
540 			}
541 
542 			fp = fopen(yylval.str, "r");
543 			if (fp != NULL)
544 			{
545 				if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
546 				{
547 					if ((current_cfe->budget_callouts_file = strdup(yylval.str)) == NULL)
548 					{
549 						logit(LL_ERR, "entry %s: budget-calloutsfile, malloc failed!", current_cfe->name);
550 						do_exit(1);
551 					}
552 					DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using calloutsfile %s", current_cfe->name, yylval.str)));
553 				}
554 				fclose(fp);
555 			}
556 		}
557 		break;
558 
559 	case CALLBACKWAIT:
560 		if (yylval.num < CALLBACKWAIT_MIN)
561 		{
562 			yylval.num = CALLBACKWAIT_MIN;
563 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: callbackwait < %d, min = %d", current_cfe->name, CALLBACKWAIT_MIN, yylval.num)));
564 		}
565 
566 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: callbackwait = %d", current_cfe->name, yylval.num)));
567 		current_cfe->callbackwait = yylval.num;
568 		break;
569 
570 	case CALLEDBACKWAIT:
571 		if (yylval.num < CALLEDBACKWAIT_MIN)
572 		{
573 			yylval.num = CALLEDBACKWAIT_MIN;
574 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: calledbackwait < %d, min = %d", current_cfe->name, CALLEDBACKWAIT_MIN, yylval.num)));
575 		}
576 
577 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: calledbackwait = %d", current_cfe->name, yylval.num)));
578 		current_cfe->calledbackwait = yylval.num;
579 		break;
580 
581 	case CONNECTPROG:
582 		if ((current_cfe->connectprog = strdup(yylval.str)) == NULL)
583 		{
584 			logit(LL_ERR, "entry %s: connectprog, malloc failed!", current_cfe->name);
585 			do_exit(1);
586 		}
587 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: connectprog = %s", current_cfe->name, yylval.str)));
588 		break;
589 
590 	case DIALOUTTYPE:
591 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialouttype = %s", current_cfe->name, yylval.str)));
592 		if (!(strcmp(yylval.str, "normal")))
593 			current_cfe->dialouttype = DIALOUT_NORMAL;
594 		else if (!(strcmp(yylval.str, "calledback")))
595 			current_cfe->dialouttype = DIALOUT_CALLEDBACK;
596 		else
597 		{
598 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialout-type\" at line %d!", lineno);
599 			config_error_flag++;
600 		}
601 		break;
602 
603 	case DIALRETRIES:
604 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialretries = %d", current_cfe->name, yylval.num)));
605 		current_cfe->dialretries = yylval.num;
606 		break;
607 
608 	case DIALRANDINCR:
609 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialrandincr = %d", current_cfe->name, yylval.booln)));
610 		current_cfe->dialrandincr = yylval.booln;
611 		break;
612 
613 	case DIRECTION:
614 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: direction = %s", current_cfe->name, yylval.str)));
615 
616 		if (!(strcmp(yylval.str, "inout")))
617 			current_cfe->inout = DIR_INOUT;
618 		else if (!(strcmp(yylval.str, "in")))
619 			current_cfe->inout = DIR_INONLY;
620 		else if (!(strcmp(yylval.str, "out")))
621 			current_cfe->inout = DIR_OUTONLY;
622 		else
623 		{
624 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"direction\" at line %d!", lineno);
625 			config_error_flag++;
626 		}
627 		break;
628 
629 	case DISCONNECTPROG:
630 		if ((current_cfe->disconnectprog = strdup(yylval.str)) == NULL)
631 		{
632 			logit(LL_ERR, "entry %s: disconnectprog, malloc failed!", current_cfe->name);
633 			do_exit(1);
634 		}
635 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: disconnectprog = %s", current_cfe->name, yylval.str)));
636 		break;
637 
638 	case DOWNTRIES:
639 		if (yylval.num > DOWN_TRIES_MAX)
640 			yylval.num = DOWN_TRIES_MAX;
641 		else if (yylval.num < DOWN_TRIES_MIN)
642 			yylval.num = DOWN_TRIES_MIN;
643 
644 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtries = %d", current_cfe->name, yylval.num)));
645 		current_cfe->downtries = yylval.num;
646 		break;
647 
648 	case DOWNTIME:
649 		if (yylval.num > DOWN_TIME_MAX)
650 			yylval.num = DOWN_TIME_MAX;
651 		else if (yylval.num < DOWN_TIME_MIN)
652 			yylval.num = DOWN_TIME_MIN;
653 
654 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtime = %d", current_cfe->name, yylval.num)));
655 		current_cfe->downtime = yylval.num;
656 		break;
657 
658 	case EARLYHANGUP:
659 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: earlyhangup = %d", current_cfe->name, yylval.num)));
660 		current_cfe->earlyhangup = yylval.num;
661 		break;
662 
663 	case EXTCALLATTR:
664 		DBGL(DL_RCCF, (logit(LL_DBG, "system: extcallattr = %d", yylval.booln)));
665 		extcallattr = yylval.booln;
666 		break;
667 
668 	case FIRMWARE:
669 		DBGL(DL_RCCF, (logit(LL_DBG, "controller %d: firmware = %s", cur_ctrl->isdnif, yylval.str)));
670 		cur_ctrl->firmware = strdup(yylval.str);
671 		break;
672 
673 	case HOLIDAYFILE:
674 		strlcpy(holidayfile, yylval.str, sizeof(holidayfile));
675 		DBGL(DL_RCCF, (logit(LL_DBG, "system: holidayfile = %s", yylval.str)));
676 		break;
677 
678 	case IDLE_ALG_OUT:
679 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle-algorithm-outgoing = %s", current_cfe->name, yylval.str)));
680 
681 		if (!(strcmp(yylval.str, "fix-unit-size")))
682 		{
683 			current_cfe->shorthold_algorithm = SHA_FIXU;
684 		}
685 		else if (!(strcmp(yylval.str, "var-unit-size")))
686 		{
687 			current_cfe->shorthold_algorithm = SHA_VARU;
688 		}
689 		else
690 		{
691 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"idle-algorithm-outgoing\" at line %d!", lineno);
692 			config_error_flag++;
693 		}
694 		break;
695 
696 	case IDLETIME_IN:
697 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle_time_in = %d", current_cfe->name, yylval.num)));
698 		current_cfe->idle_time_in = yylval.num;
699 		break;
700 
701 	case IDLETIME_OUT:
702 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle_time_out = %d", current_cfe->name, yylval.num)));
703 		current_cfe->idle_time_out = yylval.num;
704 		break;
705 
706 	case ISDNCONTROLLER:
707 		current_cfe->isdncontroller = yylval.num;
708 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdncontroller = %d", current_cfe->name, yylval.num)));
709 		break;
710 
711 	case ISDNCHANNEL:
712 		if (yylval.num == 0 || yylval.num == -1) {
713 			current_cfe->isdnchannel = CHAN_ANY;
714 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdnchannel = any", current_cfe->name)));
715 		} else if (yylval.num > MAX_BCHAN) {
716 			logit(LL_DBG, "entry %s: isdnchannel value out of range", current_cfe->name);
717 			config_error_flag++;
718 		} else {
719 			current_cfe->isdnchannel = yylval.num - 1;
720 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdnchannel = %d", current_cfe->name, yylval.num)));
721 		}
722 		break;
723 
724 	case ISDNTIME:
725 		DBGL(DL_RCCF, (logit(LL_DBG, "system: isdntime = %d", yylval.booln)));
726 		isdntime = yylval.booln;
727 		break;
728 
729 	case ISDNTXDELIN:
730 		current_cfe->isdntxdelin = yylval.num;
731 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdntxdel-incoming = %d", current_cfe->name, yylval.num)));
732 		break;
733 
734 	case ISDNTXDELOUT:
735 		current_cfe->isdntxdelout = yylval.num;
736 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdntxdel-outgoing = %d", current_cfe->name, yylval.num)));
737 		break;
738 
739 	case LOCAL_PHONE_DIALOUT:
740 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: local_phone_dialout = %s", current_cfe->name, yylval.str)));
741 		strlcpy(current_cfe->local_phone_dialout, yylval.str,
742 		    sizeof(current_cfe->local_phone_dialout));
743 		break;
744 
745 	case LOCAL_PHONE_INCOMING:
746 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: local_phone_incoming = %s", current_cfe->name, yylval.str)));
747 		strlcpy(current_cfe->local_phone_incoming, yylval.str,
748 		    sizeof(current_cfe->local_phone_incoming));
749 		break;
750 
751 	case MAILER:
752 		strlcpy(mailer, yylval.str, sizeof(mailer));
753 		DBGL(DL_RCCF, (logit(LL_DBG, "system: mailer = %s", yylval.str)));
754 		break;
755 
756 	case MAILTO:
757 		strlcpy(mailto, yylval.str, sizeof(mailto));
758 		DBGL(DL_RCCF, (logit(LL_DBG, "system: mailto = %s", yylval.str)));
759 		break;
760 
761 	case MONITORPORT:
762 		monitorport = yylval.num;
763 		DBGL(DL_RCCF, (logit(LL_DBG, "system: monitorport = %d", yylval.num)));
764 		break;
765 
766 	case MONITORSW:
767 		if (yylval.booln && inhibit_monitor)
768 		{
769 			do_monitor = 0;
770 			DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable overriden by command line flag")));
771 		}
772 		else
773 		{
774 			do_monitor = yylval.booln;
775 			DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable = %d", yylval.booln)));
776 		}
777 		break;
778 
779 	case NAME:
780 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: name = %s", current_cfe->name, yylval.str)));
781 		strlcpy(current_cfe->name, yylval.str,
782 		    sizeof(current_cfe->name));
783 		break;
784 
785 	case PPP_AUTH_RECHALLENGE:
786 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-auth-rechallenge = %d", current_cfe->name, yylval.booln)));
787 		if (yylval.booln)
788 			current_cfe->ppp_auth_flags |= AUTH_RECHALLENGE;
789 		else
790 			current_cfe->ppp_auth_flags &= ~AUTH_RECHALLENGE;
791 		break;
792 
793 	case PPP_AUTH_PARANOID:
794 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-auth-paranoid = %d", current_cfe->name, yylval.booln)));
795 		if (yylval.booln)
796 			current_cfe->ppp_auth_flags |= AUTH_REQUIRED;
797 		else
798 			current_cfe->ppp_auth_flags &= ~AUTH_REQUIRED;
799 		break;
800 
801 	case PPP_EXPECT_AUTH:
802 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-auth = %s", current_cfe->name, yylval.str)));
803 		if (!(strcmp(yylval.str, "none")))
804 			current_cfe->ppp_expect_auth = AUTH_NONE;
805 		else if (!(strcmp(yylval.str, "pap")))
806 			current_cfe->ppp_expect_auth = AUTH_PAP;
807 		else if (!(strcmp(yylval.str, "chap")))
808 			current_cfe->ppp_expect_auth = AUTH_CHAP;
809 		else
810 		{
811 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-expect-auth\" at line %d!", lineno);
812 			config_error_flag++;
813 			break;
814 		}
815 		break;
816 
817 	case PPP_EXPECT_NAME:
818 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-name = %s", current_cfe->name, yylval.str)));
819 		if (current_cfe->ppp_expect_name)
820 		    free(current_cfe->ppp_expect_name);
821 		current_cfe->ppp_expect_name = strdup(yylval.str);
822 		break;
823 
824 	case PPP_EXPECT_PASSWORD:
825 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-password = %s", current_cfe->name, yylval.str)));
826 		if (current_cfe->ppp_expect_password)
827 		    free(current_cfe->ppp_expect_password);
828 		current_cfe->ppp_expect_password = strdup(yylval.str);
829 		break;
830 
831 	case PPP_SEND_AUTH:
832 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-auth = %s", current_cfe->name, yylval.str)));
833 		if (!(strcmp(yylval.str, "none")))
834 			current_cfe->ppp_send_auth = AUTH_NONE;
835 		else if (!(strcmp(yylval.str, "pap")))
836 			current_cfe->ppp_send_auth = AUTH_PAP;
837 		else if (!(strcmp(yylval.str, "chap")))
838 			current_cfe->ppp_send_auth = AUTH_CHAP;
839 		else
840 		{
841 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-send-auth\" at line %d!", lineno);
842 			config_error_flag++;
843 			break;
844 		}
845 		break;
846 
847 	case PPP_SEND_NAME:
848 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-name = %s", current_cfe->name, yylval.str)));
849 		if (current_cfe->ppp_send_name)
850 		    free(current_cfe->ppp_send_name);
851 		current_cfe->ppp_send_name = strdup(yylval.str);
852 		break;
853 
854 	case PPP_SEND_PASSWORD:
855 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-password = %s", current_cfe->name, yylval.str)));
856 		if (current_cfe->ppp_send_password)
857 		    free(current_cfe->ppp_send_password);
858 		current_cfe->ppp_send_password = strdup(yylval.str);
859 		break;
860 
861 	case PROTOCOL:
862 		DBGL(DL_RCCF, (logit(LL_DBG, "controller %d: protocol = %s", cur_ctrl->isdnif, yylval.str)));
863 		if (!(strcmp(yylval.str, "dss1")))
864 			cur_ctrl->protocol = PROTOCOL_DSS1;
865 		else if (!(strcmp(yylval.str, "d64s")))
866 			cur_ctrl->protocol = PROTOCOL_D64S;
867 		else
868 		{
869 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"protocol\" at line %d!", lineno);
870 			config_error_flag++;
871 		}
872 		break;
873 
874 	case REACTION:
875 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialin_reaction = %s", current_cfe->name, yylval.str)));
876 		if (!(strcmp(yylval.str, "accept")))
877 			current_cfe->dialin_reaction = REACT_ACCEPT;
878 		else if (!(strcmp(yylval.str, "reject")))
879 			current_cfe->dialin_reaction = REACT_REJECT;
880 		else if (!(strcmp(yylval.str, "ignore")))
881 			current_cfe->dialin_reaction = REACT_IGNORE;
882 		else if (!(strcmp(yylval.str, "answer")))
883 			current_cfe->dialin_reaction = REACT_ANSWER;
884 		else if (!(strcmp(yylval.str, "callback")))
885 			current_cfe->dialin_reaction = REACT_CALLBACK;
886 		else
887 		{
888 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialin_reaction\" at line %d!", lineno);
889 			config_error_flag++;
890 		}
891 		break;
892 
893 	case REMOTE_PHONE_DIALOUT:
894 		if (current_cfe->remote_numbers_count >= MAXRNUMBERS)
895 		{
896 			logit(LL_ERR, "ERROR parsing config file: too many remote numbers at line %d!", lineno);
897 			config_error_flag++;
898 			break;
899 		}
900 
901 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remote_phone_dialout #%d = %s",
902 			current_cfe->name, current_cfe->remote_numbers_count, yylval.str)));
903 
904 		strlcpy(current_cfe->remote_numbers[current_cfe->remote_numbers_count].number,
905 		    yylval.str,
906 		    sizeof(current_cfe->remote_numbers[current_cfe->remote_numbers_count].number));
907 		current_cfe->remote_numbers[current_cfe->remote_numbers_count].flag = 0;
908 
909 		current_cfe->remote_numbers_count++;
910 
911 		break;
912 
913 	case REMOTE_NUMBERS_HANDLING:
914 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remdial_handling = %s", current_cfe->name, yylval.str)));
915 		if (!(strcmp(yylval.str, "next")))
916 			current_cfe->remote_numbers_handling = RNH_NEXT;
917 		else if (!(strcmp(yylval.str, "last")))
918 			current_cfe->remote_numbers_handling = RNH_LAST;
919 		else if (!(strcmp(yylval.str, "first")))
920 			current_cfe->remote_numbers_handling = RNH_FIRST;
921 		else
922 		{
923 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"remdial_handling\" at line %d!", lineno);
924 			config_error_flag++;
925 		}
926 		break;
927 
928 	case REMOTE_PHONE_INCOMING:
929 		{
930 			int n;
931 			n = current_cfe->incoming_numbers_count;
932 			if (n >= MAX_INCOMING)
933 			{
934 				logit(LL_ERR, "ERROR parsing config file: too many \"remote_phone_incoming\" entries at line %d!", lineno);
935 				config_error_flag++;
936 				break;
937 			}
938 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remote_phone_incoming #%d = %s", current_cfe->name, n, yylval.str)));
939 			strlcpy(current_cfe->remote_phone_incoming[n].number,
940 			    yylval.str,
941 			    sizeof(current_cfe->remote_phone_incoming[n].number));
942 			current_cfe->incoming_numbers_count++;
943 		}
944 		break;
945 
946 	case RATESFILE:
947 		strlcpy(ratesfile, yylval.str, sizeof(ratesfile));
948 		DBGL(DL_RCCF, (logit(LL_DBG, "system: ratesfile = %s", yylval.str)));
949 		break;
950 
951 	case RATETYPE:
952 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ratetype = %d", current_cfe->name, yylval.num)));
953 		current_cfe->ratetype = yylval.num;
954 		break;
955 
956 	case RECOVERYTIME:
957 		if (yylval.num < RECOVERYTIME_MIN)
958 		{
959 			yylval.num = RECOVERYTIME_MIN;
960 			DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: recoverytime < %d, min = %d", current_cfe->name, RECOVERYTIME_MIN, yylval.num)));
961 		}
962 
963 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: recoverytime = %d", current_cfe->name, yylval.num)));
964 		current_cfe->recoverytime = yylval.num;
965 		break;
966 
967 	case REGEXPR:
968 		if (nregexpr >= MAX_RE)
969 		{
970 			logit(LL_ERR, "system: regexpr #%d >= MAX_RE", nregexpr);
971 			config_error_flag++;
972 			break;
973 		}
974 
975 		if ((i = regcomp(&(rarr[nregexpr].re), yylval.str, REG_EXTENDED|REG_NOSUB)) != 0)
976 		{
977 			char buf[256];
978 			regerror(i, &(rarr[nregexpr].re), buf, sizeof(buf));
979 			logit(LL_ERR, "system: regcomp error for %s: [%s]", yylval.str, buf);
980 			config_error_flag++;
981 			break;
982 		}
983 		else
984 		{
985 			if ((rarr[nregexpr].re_expr = strdup(yylval.str)) == NULL)
986 			{
987 				logit(LL_ERR, "system: regexpr malloc error error for %s", yylval.str);
988 				config_error_flag++;
989 				break;
990 			}
991 
992 			DBGL(DL_RCCF, (logit(LL_DBG, "system: regexpr %s stored into slot %d", yylval.str, nregexpr)));
993 
994 			if (rarr[nregexpr].re_prog != NULL)
995 				rarr[nregexpr].re_flg = 1;
996 
997 			nregexpr++;
998 
999 		}
1000 		break;
1001 
1002 	case REGPROG:
1003 		if (nregprog >= MAX_RE)
1004 		{
1005 			logit(LL_ERR, "system: regprog #%d >= MAX_RE", nregprog);
1006 			config_error_flag++;
1007 			break;
1008 		}
1009 		if ((rarr[nregprog].re_prog = strdup(yylval.str)) == NULL)
1010 		{
1011 			logit(LL_ERR, "system: regprog malloc error error for %s", yylval.str);
1012 			config_error_flag++;
1013 			break;
1014 		}
1015 
1016 		DBGL(DL_RCCF, (logit(LL_DBG, "system: regprog %s stored into slot %d", yylval.str, nregprog)));
1017 
1018 		if (rarr[nregprog].re_expr != NULL)
1019 			rarr[nregprog].re_flg = 1;
1020 
1021 		nregprog++;
1022 		break;
1023 
1024 	case ROTATESUFFIX:
1025 		strlcpy(rotatesuffix, yylval.str, sizeof(rotatesuffix));
1026 		DBGL(DL_RCCF, (logit(LL_DBG, "system: rotatesuffix = %s", yylval.str)));
1027 		break;
1028 
1029 	case RTPRIO:
1030 #ifdef USE_RTPRIO
1031 		rt_prio = yylval.num;
1032 		if (rt_prio < RTP_PRIO_MIN || rt_prio > RTP_PRIO_MAX)
1033 		{
1034 			config_error_flag++;
1035 			logit(LL_ERR, "system: error, rtprio (%d) out of range!", yylval.num);
1036 		}
1037 		else
1038 		{
1039 			DBGL(DL_RCCF, (logit(LL_DBG, "system: rtprio = %d", yylval.num)));
1040 		}
1041 #else
1042 		rt_prio = RTPRIO_NOTUSED;
1043 #endif
1044 		break;
1045 
1046 	case TINAINITPROG:
1047 		strlcpy(tinainitprog, yylval.str, sizeof(tinainitprog));
1048 		DBGL(DL_RCCF, (logit(LL_DBG, "system: tinainitprog = %s", yylval.str)));
1049 		break;
1050 
1051 	case UNITLENGTH:
1052 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: unitlength = %d", current_cfe->name, yylval.num)));
1053 		current_cfe->unitlength = yylval.num;
1054 		break;
1055 
1056 	case UNITLENGTHSRC:
1057 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: unitlengthsrc = %s", current_cfe->name, yylval.str)));
1058 		if (!(strcmp(yylval.str, "none")))
1059 			current_cfe->unitlengthsrc = ULSRC_NONE;
1060 		else if (!(strcmp(yylval.str, "cmdl")))
1061 			current_cfe->unitlengthsrc = ULSRC_CMDL;
1062 		else if (!(strcmp(yylval.str, "conf")))
1063 			current_cfe->unitlengthsrc = ULSRC_CONF;
1064 		else if (!(strcmp(yylval.str, "rate")))
1065 			current_cfe->unitlengthsrc = ULSRC_RATE;
1066 		else if (!(strcmp(yylval.str, "aocd")))
1067 			current_cfe->unitlengthsrc = ULSRC_DYN;
1068 		else
1069 		{
1070 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"unitlengthsrc\" at line %d!", lineno);
1071 			config_error_flag++;
1072 		}
1073 		break;
1074 
1075 	case USRDEVICENAME:
1076 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usrdevicename = %s", current_cfe->name, yylval.str)));
1077 		strncpy(current_cfe->usrdevicename, yylval.str, sizeof(current_cfe->usrdevicename));
1078 		current_cfe->usrdevice = lookup_l4_driver(yylval.str);
1079 		if (current_cfe->usrdevice < 0)
1080 		{
1081 			logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"usrdevicename\" at line %d!", lineno);
1082 			config_error_flag++;
1083 		}
1084 		break;
1085 
1086 	case USRDEVICEUNIT:
1087 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usrdeviceunit = %d", current_cfe->name, yylval.num)));
1088 		current_cfe->usrdeviceunit = yylval.num;
1089 		break;
1090 
1091 	case USEACCTFILE:
1092 		useacctfile = yylval.booln;
1093 		DBGL(DL_RCCF, (logit(LL_DBG, "system: useacctfile = %d", yylval.booln)));
1094 		break;
1095 
1096 	case USEDOWN:
1097 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usedown = %d", current_cfe->name, yylval.booln)));
1098 		current_cfe->usedown = yylval.booln;
1099 		break;
1100 
1101 	case VALID:
1102 		DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: valid = %s", current_cfe->name, yylval.str)));
1103 		parse_valid(yylval.str);
1104 		break;
1105 
1106 	default:
1107 		logit(LL_ERR, "ERROR parsing config file: unknown keyword at line %d!", lineno);
1108 		config_error_flag++;
1109 		break;
1110 	}
1111 }
1112 
1113 /*---------------------------------------------------------------------------*
1114  *	parse a date/time range
1115  *---------------------------------------------------------------------------*/
1116 static void
parse_valid(char * dt)1117 parse_valid(char *dt)
1118 {
1119 	/* a valid string consists of some days of week separated by
1120 	 * commas, where 0=sunday, 1=monday .. 6=saturday and a special
1121 	 * value of 7 which is a holiday from the holiday file.
1122 	 * after the days comes an optional (!) time range in the form
1123 	 * aa:bb-cc:dd, this format is fixed to be parsable by sscanf.
1124 	 * Valid specifications looks like this:
1125 	 * 1,2,3,4,5,09:00-18:00	Monday-Friday 9-18h
1126 	 * 1,2,3,4,5,18:00-09:00	Monday-Friday 18-9h
1127 	 * 6				Saturday (whole day)
1128 	 * 0,7				Sunday and Holidays
1129 	 */
1130 
1131 	int day = 0;
1132 	int fromhr = 0;
1133 	int frommin = 0;
1134 	int tohr = 0;
1135 	int tomin = 0;
1136 	int ret;
1137 
1138 	for (;;)
1139 	{
1140 		if ( ( ((*dt >= '0') && (*dt <= '9')) && (*(dt+1) == ':') ) ||
1141 		    ( ((*dt >= '0') && (*dt <= '2')) && ((*(dt+1) >= '0') && (*(dt+1) <= '9')) && (*(dt+2) == ':') ) )
1142 		{
1143 			/* dt points to time spec */
1144 			ret = sscanf(dt, "%d:%d-%d:%d", &fromhr, &frommin, &tohr, &tomin);
1145 			if (ret !=4)
1146 			{
1147 				logit(LL_ERR, "ERROR parsing config file: timespec [%s] error at line %d!", *dt, lineno);
1148 				config_error_flag++;
1149 				return;
1150 			}
1151 
1152 			if (fromhr < 0 || fromhr > 24 || tohr < 0 || tohr > 24 ||
1153 			   frommin < 0 || frommin > 59 || tomin < 0 || tomin > 59)
1154 			{
1155 				logit(LL_ERR, "ERROR parsing config file: invalid time [%s] at line %d!", *dt, lineno);
1156 				config_error_flag++;
1157 				return;
1158 			}
1159 			break;
1160 		}
1161 		else if ((*dt >= '0') && (*dt <= '7'))
1162 		{
1163 			/* dt points to day spec */
1164 			day |= 1 << (*dt - '0');
1165 			dt++;
1166 			continue;
1167 		}
1168 		else if (*dt == ',')
1169 		{
1170 			/* dt points to delimiter */
1171 			dt++;
1172 			continue;
1173 		}
1174 		else if (*dt == '\0')
1175 		{
1176 			/* dt points to end of string */
1177 			break;
1178 		}
1179 		else
1180 		{
1181 			/* dt points to illegal character */
1182 			logit(LL_ERR, "ERROR parsing config file: illegal character [%c=0x%x] in date/time spec at line %d!", *dt, *dt, lineno);
1183 			config_error_flag++;
1184 			return;
1185 		}
1186 	}
1187 	current_cfe->day = day;
1188 	current_cfe->fromhr = fromhr;
1189 	current_cfe->frommin = frommin;
1190 	current_cfe->tohr = tohr;
1191 	current_cfe->tomin = tomin;
1192 }
1193 
1194 void
flush_config()1195 flush_config()
1196 {
1197 	if (current_cfe != NULL) {
1198 		add_cfg_entry(current_cfe);
1199 	}
1200 }
1201 
1202 /*---------------------------------------------------------------------------*
1203  *	configuration validation and consistency check
1204  *---------------------------------------------------------------------------*/
1205 static void
check_config(void)1206 check_config(void)
1207 {
1208 	struct cfg_entry *cep = NULL;
1209 	int i;
1210 	int error = 0;
1211 
1212 	/* regular expression table */
1213 
1214 	for (i=0; i < MAX_RE; i++)
1215 	{
1216 		if ((rarr[i].re_expr != NULL) && (rarr[i].re_prog == NULL))
1217 		{
1218 			logit(LL_ERR, "check_config: regular expression %d without program!", i);
1219 			error++;
1220 		}
1221 		if ((rarr[i].re_prog != NULL) && (rarr[i].re_expr == NULL))
1222 		{
1223 			logit(LL_ERR, "check_config: regular expression program %d without expression!", i);
1224 			error++;
1225 		}
1226 	}
1227 
1228 	/* entry sections */
1229 
1230 	for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
1231 
1232 		/* does this entry have a bchannel driver configured? */
1233 		if (cep->usrdevice < 0) {
1234 			logit(LL_ERR, "check_config: usrdevicename not set in entry \"%s\"!",
1235 			    cep->name);
1236 			error++;
1237 		}
1238 		if (cep->usrdeviceunit < 0) {
1239 			logit(LL_ERR, "check_config: usrdeviceunit not set in entry \"%s\"!",
1240 			    cep->name);
1241 			error++;
1242 		}
1243 
1244 		/* numbers used for dialout */
1245 
1246 		if ((cep->inout != DIR_INONLY) && (cep->dialin_reaction != REACT_ANSWER))
1247 		{
1248 			if (cep->remote_numbers_count == 0)
1249 			{
1250 				logit(LL_ERR, "check_config: remote-phone-dialout not set in entry \"%s\"!",
1251 				    cep->name);
1252 				error++;
1253 			}
1254 		}
1255 
1256 		/* numbers used for incoming calls */
1257 
1258 		if (cep->inout != DIR_OUTONLY)
1259 		{
1260 			if (strlen(cep->local_phone_incoming) == 0)
1261 			{
1262 				logit(LL_ERR, "check_config: local-phone-incoming not set in entry \"%s\"!",
1263 				    cep->name);
1264 				error++;
1265 			}
1266 			if (cep->incoming_numbers_count == 0)
1267 			{
1268 				logit(LL_ERR, "check_config: remote-phone-incoming not set in entry \"%s\"!",
1269 				    cep->name);
1270 				error++;
1271 			}
1272 		}
1273 
1274 		if ((cep->dialin_reaction == REACT_ANSWER) && (cep->b1protocol != BPROT_NONE))
1275 		{
1276 			logit(LL_ERR, "check_config: b1protocol not raw for telephony in entry \"%s\"!",
1277 			    cep->name);
1278 			error++;
1279 		}
1280 
1281 		if ((cep->ppp_send_auth == AUTH_PAP) || (cep->ppp_send_auth == AUTH_CHAP))
1282 		{
1283 			if (cep->ppp_send_name == NULL)
1284 			{
1285 				logit(LL_ERR, "check_config: no remote authentification name in entry \"%s\"!",
1286 				    cep->name);
1287 				error++;
1288 			}
1289 			if (cep->ppp_send_password == NULL)
1290 			{
1291 				logit(LL_ERR, "check_config: no remote authentification password in entry \"%s\"!",
1292 				    cep->name);
1293 				error++;
1294 			}
1295 		}
1296 		if ((cep->ppp_expect_auth == AUTH_PAP) || (cep->ppp_expect_auth == AUTH_CHAP))
1297 		{
1298 			if (cep->ppp_expect_name == NULL)
1299 			{
1300 				logit(LL_ERR, "check_config: no local authentification name in entry \"%s\"!",
1301 				    cep->name);
1302 				error++;
1303 			}
1304 			if (cep->ppp_expect_password == NULL)
1305 			{
1306 				logit(LL_ERR, "check_config: no local authentification secret in entry \"%s\"!",
1307 				    cep->name);
1308 				error++;
1309 			}
1310 		}
1311 
1312 #ifdef SPPPGETAUTHCFG
1313 		if (cep->ppp_expect_auth != AUTH_UNDEF
1314 		   || cep->ppp_send_auth != AUTH_UNDEF)
1315 			set_isppp_auth(cep);
1316 #endif
1317 
1318 		/*
1319 		 * Only if AUTOUPDOWN_YES is the only bit set, otherwise
1320 		 * we already have handled this interface.
1321 		 */
1322 		if (cep->autoupdown == AUTOUPDOWN_YES)
1323 			set_autoupdown(cep);
1324 	}
1325 	if (error) {
1326 		logit(LL_ERR, "check_config: %d error(s) in configuration file, exiting!",
1327 		    error);
1328 		do_exit(1);
1329 	}
1330 }
1331 
1332 /*---------------------------------------------------------------------------*
1333  *	print the configuration
1334  *---------------------------------------------------------------------------*/
1335 static void
print_config(void)1336 print_config(void)
1337 {
1338 #define PFILE stdout
1339 
1340 #ifdef I4B_EXTERNAL_MONITOR
1341 	extern struct monitor_rights * monitor_next_rights(const struct monitor_rights *r);
1342 	struct monitor_rights *m_rights;
1343 #endif
1344 	struct cfg_entry *cep = NULL;
1345 	int i, j;
1346 	time_t clock;
1347 	char mytime[64];
1348 
1349 	time(&clock);
1350 	strlcpy(mytime, ctime(&clock), sizeof(mytime));
1351 	mytime[strlen(mytime)-1] = '\0';
1352 
1353 	fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1354 	fprintf(PFILE, "# system section (generated %s)\n", mytime);
1355 	fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1356 	fprintf(PFILE, "system\n");
1357 	fprintf(PFILE, "useacctfile     = %s\n", useacctfile ? "on\t\t\t\t# update accounting information file" : "off\t\t\t\t# don't update accounting information file");
1358 	fprintf(PFILE, "acctall         = %s\n", acct_all ? "on\t\t\t\t# put all events into accounting file" : "off\t\t\t\t# put only charged events into accounting file");
1359 	fprintf(PFILE, "acctfile        = %s\t\t# accounting information file\n", acctfile);
1360 	fprintf(PFILE, "ratesfile       = %s\t\t# charging rates database file\n", ratesfile);
1361 
1362 #ifdef USE_RTPRIO
1363 	if (rt_prio == RTPRIO_NOTUSED)
1364 		fprintf(PFILE, "# rtprio is unused\n");
1365 	else
1366 		fprintf(PFILE, "rtprio          = %d\t\t\t\t# isdnd runs at realtime priority\n", rt_prio);
1367 #endif
1368 
1369 	/* regular expression table */
1370 
1371 	for (i=0; i < MAX_RE; i++)
1372 	{
1373 		if (rarr[i].re_expr != NULL)
1374 		{
1375 			fprintf(PFILE, "regexpr         = \"%s\"\t\t# scan logfile for this expression\n", rarr[i].re_expr);
1376 		}
1377 		if (rarr[i].re_prog != NULL)
1378 		{
1379 			fprintf(PFILE, "regprog         = %s\t\t# program to run when expression is matched\n", rarr[i].re_prog);
1380 		}
1381 	}
1382 
1383 #ifdef I4B_EXTERNAL_MONITOR
1384 
1385 	fprintf(PFILE, "monitor-allowed = %s\n", do_monitor ? "on\t\t\t\t# remote isdnd monitoring allowed" : "off\t\t\t\t# remote isdnd monitoring disabled");
1386 	fprintf(PFILE, "monitor-port    = %d\t\t\t\t# TCP/IP port number used for remote monitoring\n", monitorport);
1387 
1388 	m_rights = monitor_next_rights(NULL);
1389 	if (m_rights != NULL)
1390 	{
1391 		char *s = "error\n";
1392 		char b[512];
1393 
1394 		for ( ; m_rights != NULL; m_rights = monitor_next_rights(m_rights))
1395 		{
1396 			if (m_rights->local)
1397 			{
1398 				fprintf(PFILE, "monitor         = \"%s\"\t\t# local socket name for monitoring\n", m_rights->name);
1399 			}
1400 			else
1401 			{
1402 				struct in_addr ia;
1403 				ia.s_addr = ntohl(m_rights->net);
1404 
1405 				switch (m_rights->mask)
1406 				{
1407 				case 0xffffffff:
1408 					s = "32";
1409 					break;
1410 				case 0xfffffffe:
1411 					s = "31";
1412 					break;
1413 				case 0xfffffffc:
1414 					s = "30";
1415 					break;
1416 				case 0xfffffff8:
1417 					s = "29";
1418 					break;
1419 				case 0xfffffff0:
1420 					s = "28";
1421 					break;
1422 				case 0xffffffe0:
1423 					s = "27";
1424 					break;
1425 				case 0xffffffc0:
1426 					s = "26";
1427 					break;
1428 				case 0xffffff80:
1429 					s = "25";
1430 					break;
1431 				case 0xffffff00:
1432 					s = "24";
1433 					break;
1434 				case 0xfffffe00:
1435 					s = "23";
1436 					break;
1437 				case 0xfffffc00:
1438 					s = "22";
1439 					break;
1440 				case 0xfffff800:
1441 					s = "21";
1442 					break;
1443 				case 0xfffff000:
1444 					s = "20";
1445 					break;
1446 				case 0xffffe000:
1447 					s = "19";
1448 					break;
1449 				case 0xffffc000:
1450 					s = "18";
1451 					break;
1452 				case 0xffff8000:
1453 					s = "17";
1454 					break;
1455 				case 0xffff0000:
1456 					s = "16";
1457 					break;
1458 				case 0xfffe0000:
1459 					s = "15";
1460 					break;
1461 				case 0xfffc0000:
1462 					s = "14";
1463 					break;
1464 				case 0xfff80000:
1465 					s = "13";
1466 					break;
1467 				case 0xfff00000:
1468 					s = "12";
1469 					break;
1470 				case 0xffe00000:
1471 					s = "11";
1472 					break;
1473 				case 0xffc00000:
1474 					s = "10";
1475 					break;
1476 				case 0xff800000:
1477 					s = "9";
1478 					break;
1479 				case 0xff000000:
1480 					s = "8";
1481 					break;
1482 				case 0xfe000000:
1483 					s = "7";
1484 					break;
1485 				case 0xfc000000:
1486 					s = "6";
1487 					break;
1488 				case 0xf8000000:
1489 					s = "5";
1490 					break;
1491 				case 0xf0000000:
1492 					s = "4";
1493 					break;
1494 				case 0xe0000000:
1495 					s = "3";
1496 					break;
1497 				case 0xc0000000:
1498 					s = "2";
1499 					break;
1500 				case 0x80000000:
1501 					s = "1";
1502 					break;
1503 				case 0x00000000:
1504 					s = "0";
1505 					break;
1506 				}
1507 				fprintf(PFILE, "monitor         = \"%s/%s\"\t\t# host (net/mask) allowed to connect for monitoring\n", inet_ntoa(ia), s);
1508 			}
1509 			b[0] = '\0';
1510 
1511 			if ((m_rights->rights) & I4B_CA_COMMAND_FULL)
1512 				strlcat(b, "fullcmd,", sizeof(b));
1513 			if ((m_rights->rights) & I4B_CA_COMMAND_RESTRICTED)
1514 				strlcat(b, "restrictedcmd,", sizeof(b));
1515 			if ((m_rights->rights) & I4B_CA_EVNT_CHANSTATE)
1516 				strlcat(b, "channelstate,", sizeof(b));
1517 			if ((m_rights->rights) & I4B_CA_EVNT_CALLIN)
1518 				strlcat(b, "callin,", sizeof(b));
1519 			if ((m_rights->rights) & I4B_CA_EVNT_CALLOUT)
1520 				strlcat(b, "callout,", sizeof(b));
1521 			if ((m_rights->rights) & I4B_CA_EVNT_I4B)
1522 				strlcat(b, "logevents,", sizeof(b));
1523 
1524 			if (strlen(b) > 0 && b[strlen(b)-1] == ',')
1525 				b[strlen(b)-1] = '\0';
1526 
1527 			fprintf(PFILE, "monitor-access  = %s\t\t# monitor access rights\n", b);
1528 		}
1529 	}
1530 
1531 #endif
1532 	/* entry sections */
1533 
1534 	for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
1535 		fprintf(PFILE, "\n");
1536 		fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1537 		fprintf(PFILE, "# entry section %d\n", i);
1538 		fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1539 		fprintf(PFILE, "entry\n");
1540 
1541 		fprintf(PFILE, "name                  = %s\t\t# name for this entry section\n", cep->name);
1542 
1543 		fprintf(PFILE, "isdncontroller        = %d\t\t# ISDN card number used for this entry\n", cep->isdncontroller);
1544 		fprintf(PFILE, "isdnchannel           = ");
1545 		switch (cep->isdnchannel)
1546 		{
1547 		case CHAN_ANY:
1548 			fprintf(PFILE, "-1\t\t# any ISDN B-channel may be used\n");
1549 			break;
1550 		default:
1551 			fprintf(PFILE, "1\t\t# only ISDN B-channel %d may be used\n", cep->isdnchannel);
1552 			break;
1553 		}
1554 
1555 		fprintf(PFILE, "usrdevicename         = %s\t\t# name of userland ISDN B-channel device\n", cep->usrdevicename);
1556 		fprintf(PFILE, "usrdeviceunit         = %d\t\t# unit number of userland ISDN B-channel device\n", cep->usrdeviceunit);
1557 
1558 		fprintf(PFILE, "b1protocol            = %s\n", cep->b1protocol ? "hdlc\t\t# B-channel layer 1 protocol is HDLC" : "raw\t\t# No B-channel layer 1 protocol used");
1559 
1560 		fprintf(PFILE, "direction             = ");
1561 		switch (cep->inout)
1562 		{
1563 		case DIR_INONLY:
1564 			fprintf(PFILE, "in\t\t# only incoming connections allowed\n");
1565 			break;
1566 		case DIR_OUTONLY:
1567 			fprintf(PFILE, "out\t\t# only outgoing connections allowed\n");
1568 			break;
1569 		case DIR_INOUT:
1570 			fprintf(PFILE, "inout\t\t# incoming and outgoing connections allowed\n");
1571 			break;
1572 		}
1573 
1574 		if (cep->remote_numbers_count > 1)
1575 		{
1576 			for (j = 0; j < cep->remote_numbers_count; j++)
1577 				fprintf(PFILE, "remote-phone-dialout  = %s\t\t# telephone number %d for dialing out to remote\n", cep->remote_numbers[j].number, j+1);
1578 
1579 				fprintf(PFILE, "remdial-handling      = ");
1580 
1581 				switch (cep->remote_numbers_handling)
1582 				{
1583 				case RNH_NEXT:
1584 					fprintf(PFILE, "next\t\t# use next number after last successful for new dial\n");
1585 					break;
1586 				case RNH_LAST:
1587 					fprintf(PFILE, "last\t\t# use last successful number for new dial\n");
1588 					break;
1589 				case RNH_FIRST:
1590 					fprintf(PFILE, "first\t\t# always start with first number for new dial\n");
1591 					break;
1592 				}
1593 			}
1594 
1595 			if (cep->local_phone_dialout[0])
1596 				fprintf(PFILE, "local-phone-dialout   = %s\t\t# show this number to remote when dialling out\n",
1597 				    cep->local_phone_dialout);
1598 			fprintf(PFILE, "dialout-type          = %s\n", cep->dialouttype ? "calledback\t\t# i am called back by remote" : "normal\t\t# i am not called back by remote");
1599 		}
1600 
1601 		if (!(cep->inout == DIR_OUTONLY))
1602 		{
1603 			int n;
1604 
1605 			fprintf(PFILE, "local-phone-incoming  = %s\t\t# incoming calls must match this (mine) telephone number\n", cep->local_phone_incoming);
1606 			for (n = 0; n < cep->incoming_numbers_count; n++)
1607 				fprintf(PFILE, "remote-phone-incoming = %s\t\t# this is a valid remote number to call me\n",
1608 					cep->remote_phone_incoming[n].number);
1609 
1610 			fprintf(PFILE, "dialin-reaction       = ");
1611 			switch (cep->dialin_reaction)
1612 			{
1613 			case REACT_ACCEPT:
1614 				fprintf(PFILE, "accept\t\t# i accept a call from remote and connect\n");
1615 				break;
1616 			case REACT_REJECT:
1617 				fprintf(PFILE, "reject\t\t# i reject the call from remote\n");
1618 				break;
1619 			case REACT_IGNORE:
1620 				fprintf(PFILE, "ignore\t\t# i ignore the call from remote\n");
1621 				break;
1622 			case REACT_ANSWER:
1623 				fprintf(PFILE, "answer\t\t# i will start telephone answering when remote calls in\n");
1624 				break;
1625 			case REACT_CALLBACK:
1626 				fprintf(PFILE, "callback\t\t# when remote calls in, i will hangup and call back\n");
1627 				break;
1628 			}
1629 		}
1630 
1631 		{
1632 			char *s;
1633 			switch (cep->ppp_expect_auth)
1634 			{
1635 			case AUTH_NONE:
1636 				s = "none";
1637 				break;
1638 			case AUTH_PAP:
1639 				s = "pap";
1640 				break;
1641 			case AUTH_CHAP:
1642 				s = "chap";
1643 				break;
1644 			default:
1645 				s = NULL;
1646 				break;
1647 			}
1648 			if (s != NULL)
1649 			{
1650 				fprintf(PFILE, "ppp-expect-auth       = %s\t\t# the auth protocol we expect to receive on dial-in (none,pap,chap)\n", s);
1651 				if (cep->ppp_expect_auth != AUTH_NONE)
1652 				{
1653 					fprintf(PFILE, "ppp-expect-name       = %s\t\t# the user name allowed in\n", cep->ppp_expect_name);
1654 					fprintf(PFILE, "ppp-expect-password   = %s\t\t# the key expected from the other side\n", cep->ppp_expect_password);
1655 					fprintf(PFILE, "ppp-auth-paranoid     = %s\t\t# do we require remote to authenticate even if we dial out\n", cep->ppp_auth_flags & AUTH_REQUIRED ? "yes" : "no");
1656 				}
1657 			}
1658 			switch (cep->ppp_send_auth)
1659 			{
1660 			case AUTH_NONE:
1661 				s = "none";
1662 				break;
1663 			case AUTH_PAP:
1664 				s = "pap";
1665 				break;
1666 			case AUTH_CHAP:
1667 				s = "chap";
1668 				break;
1669 			default:
1670 				s = NULL;
1671 				break;
1672 			}
1673 			if (s != NULL)
1674 			{
1675 				fprintf(PFILE, "ppp-send-auth         = %s\t\t# the auth protocol we use when dialing out (none,pap,chap)\n", s);
1676 				if (cep->ppp_send_auth != AUTH_NONE)
1677 				{
1678 					fprintf(PFILE, "ppp-send-name         = %s\t\t# our PPP account used for dial-out\n", cep->ppp_send_name);
1679 					fprintf(PFILE, "ppp-send-password     = %s\t\t# the key sent to the other side\n", cep->ppp_send_password);
1680 				}
1681 			}
1682 			if (cep->ppp_send_auth == AUTH_CHAP ||
1683 			   cep->ppp_expect_auth == AUTH_CHAP) {
1684 				fprintf(PFILE, "ppp-auth-rechallenge   = %s\t\t# rechallenge CHAP connections once in a while\n", cep->ppp_auth_flags & AUTH_RECHALLENGE ? "yes" : "no");
1685 			}
1686 		}
1687 
1688 		if (cep->autoupdown == AUTOUPDOWN_NO)
1689 			fprintf(PFILE, "autoupdown = no\n");
1690 
1691 		{
1692 			char *s;
1693 			fprintf(PFILE, "idletime-outgoing     = %d\t\t# outgoing call idle timeout\n", cep->idle_time_out);
1694 
1695 			switch ( cep->shorthold_algorithm )
1696 			{
1697 			case SHA_FIXU:
1698 				s = "fix-unit-size";
1699 				break;
1700 			case SHA_VARU:
1701 				s = "var-unit-size";
1702 				break;
1703 			default:
1704 				s = "error!!!";
1705 				break;
1706 			}
1707 
1708 			fprintf(PFILE, "idle-algorithm-outgoing     = %s\t\t# outgoing call idle algorithm\n", s);
1709 		}
1710 
1711 		if (!(cep->inout == DIR_OUTONLY))
1712 			fprintf(PFILE, "idletime-incoming     = %d\t\t# incoming call idle timeout\n", cep->idle_time_in);
1713 
1714 		{
1715 	 		fprintf(PFILE, "unitlengthsrc         = ");
1716 			switch (cep->unitlengthsrc)
1717 			{
1718 			case ULSRC_NONE:
1719 				fprintf(PFILE, "none\t\t# no unit length specified, using default\n");
1720 				break;
1721 			case ULSRC_CMDL:
1722 				fprintf(PFILE, "cmdl\t\t# using unit length specified on commandline\n");
1723 				break;
1724 			case ULSRC_CONF:
1725 				fprintf(PFILE, "conf\t\t# using unitlength specified by unitlength-keyword\n");
1726 				fprintf(PFILE, "unitlength            = %d\t\t# fixed unitlength\n", cep->unitlength);
1727 				break;
1728 			case ULSRC_RATE:
1729 				fprintf(PFILE, "rate\t\t# using unitlength specified in rate database\n");
1730 				fprintf(PFILE, "ratetype              = %d\t\t# type of rate from rate database\n", cep->ratetype);
1731 				break;
1732 			case ULSRC_DYN:
1733 				fprintf(PFILE, "aocd\t\t# using dynamically calculated unitlength based on AOCD subscription\n");
1734 				fprintf(PFILE, "ratetype              = %d\t\t# type of rate from rate database\n", cep->ratetype);
1735 				break;
1736 			}
1737 
1738 			fprintf(PFILE, "earlyhangup           = %d\t\t# early hangup safety time\n", cep->earlyhangup);
1739 
1740 		}
1741 
1742 		{
1743 			fprintf(PFILE, "answerprog            = %s\t\t# program used to answer incoming telephone calls\n", cep->answerprog);
1744 			fprintf(PFILE, "alert                 = %d\t\t# number of seconds to wait before accepting a call\n", cep->alert);
1745 		}
1746 
1747 		{
1748 			if (cep->dialin_reaction == REACT_CALLBACK)
1749 				fprintf(PFILE, "callbackwait          = %d\t\t# i am waiting this time before calling back remote\n", cep->callbackwait);
1750 
1751 			if (cep->dialouttype == DIALOUT_CALLEDBACK)
1752 				fprintf(PFILE, "calledbackwait        = %d\t\t# i am waiting this time for a call back from remote\n", cep->calledbackwait);
1753 
1754 			if (!(cep->inout == DIR_INONLY))
1755 			{
1756 				fprintf(PFILE, "dialretries           = %d\t\t# number of dialing retries\n", cep->dialretries);
1757 				fprintf(PFILE, "recoverytime          = %d\t\t# time to wait between dialling retries\n", cep->recoverytime);
1758 				fprintf(PFILE, "dialrandincr          = %s\t\t# use random dialing time addon\n", cep->dialrandincr ? "on" : "off");
1759 
1760 				fprintf(PFILE, "usedown               = %s\n", cep->usedown ? "on\t\t# ISDN device switched off on excessive dial failures" : "off\t\t# no device switchoff on excessive dial failures");
1761 				if (cep->usedown)
1762 				{
1763 					fprintf(PFILE, "downtries             = %d\t\t# number of dialretries failures before switching off\n", cep->downtries);
1764 					fprintf(PFILE, "downtime              = %d\t\t# time device is switched off\n", cep->downtime);
1765 				}
1766 			}
1767 	}
1768 	fprintf(PFILE, "\n");
1769 }
1770 
1771 static int
lookup_l4_driver(const char * name)1772 lookup_l4_driver(const char *name)
1773 {
1774 	msg_l4driver_lookup_t query;
1775 	int e;
1776 
1777 	memset(&query, 0, sizeof query);
1778 	strncpy(query.name, name, sizeof query.name);
1779 	e = ioctl(isdnfd, I4B_L4DRIVER_LOOKUP, &query);
1780 	if (e != 0) return -1;
1781 	return query.driver_id;
1782 }
1783