1/*
2 * pptpd.c
3 *
4 * Grabs any command line argument and processes any further options in
5 * the pptpd config file, before throwing over to pptpmanager.c.
6 *
7 * $Id: pptpd.c,v 1.18 2006/09/04 23:17:25 quozl Exp $
8 */
9
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#ifdef __linux__
15#define _GNU_SOURCE 1		/* strdup() prototype, broken arpa/inet.h */
16#endif
17
18#ifdef __svr4__
19#define __EXTENSIONS__ 1	/* strdup() prototype */
20#endif
21
22#ifdef __sgi__
23#define _XOPEN_SOURCE 500	/* strdup() prototype */
24#endif
25
26#include "our_syslog.h"
27#include "our_getopt.h"
28
29#include <fcntl.h>
30#include <netdb.h>
31#include <signal.h>
32#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <sys/wait.h>
40#include <sys/stat.h>
41#include <unistd.h>
42
43#include "configfile.h"
44#include "defaults.h"
45#include "compat.h"
46#include "pptpmanager.h"
47
48#ifdef CONFIG_NETtel
49#include <linux/ledman.h>
50#endif
51
52/* command line arg variables */
53char *ppp_binary = NULL;
54char *pppdoptstr = NULL;
55char *speedstr = NULL;
56char *bindaddr = NULL;
57#ifdef BCRELAY
58char *bcrelay = NULL;
59#endif
60int pptp_debug = 0;
61int pptp_noipparam = 0;
62int pptp_logwtmp = 0;
63int pptp_delegate = 0;
64
65int pptp_stimeout = STIMEOUT_DEFAULT;
66int pptp_ptimeout = PTIMEOUT_DEFAULT;
67
68int pptp_connections = CONNECTIONS_DEFAULT;
69
70int keep_connections=0;
71
72/* Local prototypes */
73static void processIPStr(int type, char *ipstr);
74
75#ifndef HAVE_DAEMON
76static void my_daemon(int argc, char **argv);
77#endif
78
79static void log_pid(char *pid_file);
80static char *lookup(char *);
81
82#ifdef BCRELAY
83static void launch_bcrelay();
84static pid_t bcrelayfork;
85#endif
86
87static void showversion()
88{
89	printf("accel-pptpd v%s  ", VERSION);
90	printf("compiled for pppd-%s, linux-%s\n",PPPD_VERSION,KERNELVERSION);
91}
92static void showusage(char *prog)
93{
94	showversion();
95	printf("Usage: pptpd [options], where options are:\n\n");
96#ifdef BCRELAY
97	printf(" [-b] [--bcrelay if]       Use broadcast relay for broadcasts comming from.\n");
98	printf("                           the specified interface (default is eth1).\n");
99#endif
100	printf(" [-c] [--conf file]        Specifies the config file to read default\n");
101	printf("                           settings from (default is %s).\n", PPTPD_CONFIG_FILE_DEFAULT);
102	printf(" [-d] [--debug]            Turns on debugging (to syslog).\n");
103	printf(" [-e] [--ppp file]         Use alternate pppd binary, default %s.\n", PPP_BINARY);
104	printf(" [-f] [--fg]               Run in foreground.\n");
105	printf(" [-h] [--help]             Displays this help message.\n");
106	printf(" [-i] [--noipparam]        Suppress the passing of the client's IP address\n");
107	printf("                           to PPP, which is done by default otherwise.\n");
108	printf(" [-l] [--listen x.x.x.x]   Specifies IP of local interface to listen to.\n");
109#if !defined(BSDUSER_PPP)
110	printf(" [-o] [--option file]      Specifies the PPP options file to use\n");
111	printf("                           (default is /etc/ppp/options).\n");
112#endif
113	printf(" [-p] [--pidfile file]     Specifies the file to write the process ID to\n");
114	printf("                           (default is /var/run/pptpd.pid).\n");
115#if !defined(BSDUSER_PPP)
116	printf(" [-s] [--speed baud]       Specifies the baud speed for the PPP daemon\n");
117	printf("                           (default is 115200).\n");
118#endif
119	printf(" [-t] [--stimeout seconds] Specifies the timeout for the first packet. This is a DOS protection\n");
120	printf("                           (default is 10).\n");
121	printf(" [-T] [--ptimeout msec]     Specifies the maximum timeout for the packet.\n");
122	printf("                           (default is 1000).\n");
123	printf(" [-v] [--version]          Displays the pptpd version number.\n");
124	printf(" [-w] [--logwtmp]          Update wtmp as users login.\n");
125	printf(" [-C] [--connections n]    Limit on number of connections.\n");
126	printf(" [-D] [--delegate]         Delegate IP allocation to pppd.\n");
127	printf(" [-k] [--keep]             Keep connections after exit.\n");
128	printf("                           (default do not keep).\n");
129
130	printf("\n\nLogs and debugging go to syslog as DAEMON.");
131
132	printf("\n\nCommand line options will override any default settings and any settings\n");
133	printf("specified in the config file (default config file: %s).\n\n", PPTPD_CONFIG_FILE_DEFAULT);
134}
135
136
137
138int main(int argc, char **argv)
139{
140	/* command line options */
141	int c;
142
143	/* function-local options */
144	int foreground = FALSE;
145	char *pid_file = NULL;
146
147	/* config file */
148	char *configFile = NULL;
149
150	/* config file parsing temp strings */
151	char tmp[MAX_CONFIG_STRING_SIZE], *tmpstr;
152
153	/* open a connection to the syslog daemon */
154	openlog("pptpd", LOG_PID, PPTP_FACILITY);
155	syslog(LOG_ERR, "MGR: Config file not found!");
156
157	/* process command line options */
158	while (1) {
159		int option_index = 0;
160#ifdef BCRELAY
161		char *optstring = "b:c:de:fhil:o:p:s:t:T:vwC:Dk";
162#else
163		char *optstring = "c:de:fhil:o:p:s:t:T:vwC:Dk";
164#endif
165
166		static struct option long_options[] =
167		{
168#ifdef BCRELAY
169			{"bcrelay", 1, 0, 0},
170#endif
171			{"conf", 1, 0, 'c'},
172			{"debug", 0, 0, 'd'},
173			{"ppp", 1, 0, 'e'},
174			{"fg", 0, 0, 'f'},
175			{"help", 0, 0, 'h'},
176			{"noipparam", 0, 0, 'i'},
177			{"listen", 1, 0, 'l'},
178			{"option", 1, 0, 'o'},
179			{"pidfile", 1, 0, 'p'},
180			{"speed", 1, 0, 's'},
181			{"stimeout", 1, 0, 't'},
182			{"ptimeout", 1, 0, 'T'},
183			{"version", 0, 0, 'v'},
184			{"logwtmp", 0, 0, 'w'},
185			{"connections", 1, 0, 'C'},
186			{"delegate", 0, 0, 'D'},
187			{"keep", 0, 0, 'k'},
188			{0, 0, 0, 0}
189		};
190
191		c = getopt_long(argc, argv, optstring, long_options, &option_index);
192		if (c == -1)
193			break;
194		/* convert long options to short form */
195		if (c == 0)
196#ifdef BCRELAY
197			c = "bcdefhilopstvwCDk"[option_index];
198#else
199			c = "cdefhilopstvwCDk"[option_index];
200#endif
201		switch (c) {
202#ifdef BCRELAY
203		case 'b': /* --bcrelay */
204			if (bcrelay) free(bcrelay);
205			bcrelay = strdup(optarg);
206			break;
207#endif
208
209		case 'l': /* --listen */
210			tmpstr = lookup(optarg);
211			if (!tmpstr) {
212				syslog(LOG_ERR, "MGR: Invalid listening address: %s!", optarg);
213				return 1;
214			}
215			if (bindaddr) free(bindaddr);
216			bindaddr = strdup(tmpstr);
217			break;
218
219		case 'h': /* --help */
220			showusage(argv[0]);
221			return 0;
222
223		case 'i': /* --noipparam */
224			pptp_noipparam = TRUE;
225			break;
226
227		case 'e': /* --ppp */
228			if (ppp_binary) free(ppp_binary);
229			ppp_binary = strdup(optarg);
230			break;
231
232		case 'd': /* --debug */
233			pptp_debug = TRUE;
234			break;
235
236		case 'f': /* --fg */
237			foreground = TRUE;
238			break;
239
240		case 'v': /* --version */
241			showversion();
242			return 0;
243
244		case 'w': /* --logwtmp */
245		        pptp_logwtmp = TRUE;
246			break;
247
248		case 'C': /* --connections */
249		        pptp_connections = atoi(optarg);
250			break;
251
252		case 'D': /* --delegate */
253		        pptp_delegate = TRUE;
254			break;
255
256		case 'o': /* --option */
257			if (pppdoptstr) free(pppdoptstr);
258			pppdoptstr = strdup(optarg);
259			break;
260
261		case 'p': /* --pidfile */
262			if (pid_file) free(pid_file);
263			pid_file = strdup(optarg);
264			break;
265
266		case 's': /* --speed */
267			if (speedstr) free(speedstr);
268			speedstr = strdup(optarg);
269			break;
270
271		case 't': /* --stimeout */
272			pptp_stimeout = atoi(optarg);
273			break;
274
275		case 'T': /* --stimeout */
276			pptp_ptimeout = atoi(optarg);
277			break;
278		case 'k': /* --keep */
279			keep_connections = 1;
280			break;
281
282		case 'c': /* --conf */
283			{
284				FILE *f;
285				if (!(f = fopen(optarg, "r"))) {
286					syslog(LOG_ERR, "MGR: Config file not found!");
287					return 1;
288				}
289				fclose(f);
290				if(configFile) free(configFile);
291				configFile = strdup(optarg);
292				break;
293			}
294
295		default:
296			showusage(argv[0]);
297			return 1;
298		}
299	}
300
301	/* Now that we have all the command line args.. lets open the
302	 * conf file and add anything else (remembering not to override
303	 * anything since the command line has more privilages :-)
304	 */
305
306	if (!configFile)
307		configFile = strdup(PPTPD_CONFIG_FILE_DEFAULT);
308
309	if (read_config_file(configFile, CONNECTIONS_KEYWORD, tmp) > 0) {
310		pptp_connections = atoi(tmp);
311		if (pptp_connections <= 0)
312			pptp_connections = CONNECTIONS_DEFAULT;
313	}
314
315	slot_init(pptp_connections);
316
317	if (!pptp_debug && read_config_file(configFile, DEBUG_KEYWORD, tmp) > 0)
318		pptp_debug = TRUE;
319
320#ifdef BCRELAY
321	if (!bcrelay && read_config_file(configFile, BCRELAY_KEYWORD, tmp) > 0)
322		bcrelay = strdup(tmp);
323#endif
324
325	if (!pptp_stimeout && read_config_file(configFile, STIMEOUT_KEYWORD, tmp) > 0) {
326		pptp_stimeout = atoi(tmp);
327		if (pptp_stimeout <= 0)
328			pptp_stimeout = STIMEOUT_DEFAULT;
329	}
330
331	if (!pptp_ptimeout && read_config_file(configFile, PTIMEOUT_KEYWORD, tmp) > 0) {
332		pptp_ptimeout = atoi(tmp);
333		if (pptp_ptimeout <= 0)
334			pptp_ptimeout = PTIMEOUT_DEFAULT;
335	}
336
337	if (!pptp_noipparam && read_config_file(configFile, NOIPPARAM_KEYWORD, tmp) > 0) {
338		pptp_noipparam = TRUE;
339	}
340
341	if (!bindaddr && read_config_file(configFile, LISTEN_KEYWORD, tmp) > 0) {
342		tmpstr = lookup(tmp);
343		if(!tmpstr) {
344			syslog(LOG_ERR, "MGR: Invalid listening address: %s!", tmp);
345			return 1;
346		}
347		bindaddr = strdup(tmpstr);
348	}
349
350	if (!speedstr && read_config_file(configFile, SPEED_KEYWORD, tmp) > 0)
351		speedstr = strdup(tmp);
352
353	if (!pppdoptstr && read_config_file(configFile, PPPD_OPTION_KEYWORD, tmp) > 0) {
354		pppdoptstr = strdup(tmp);
355	}
356
357	if (!ppp_binary && read_config_file(configFile, PPP_BINARY_KEYWORD, tmp) > 0) {
358		ppp_binary = strdup(tmp);
359	}
360
361	if (!pptp_logwtmp && read_config_file(configFile, LOGWTMP_KEYWORD, tmp) > 0) {
362		pptp_logwtmp = TRUE;
363	}
364
365	if (!pptp_delegate && read_config_file(configFile, DELEGATE_KEYWORD, tmp) > 0) {
366		pptp_delegate = TRUE;
367	}
368
369	if (read_config_file(configFile, KEEP_KEYWORD, tmp) > 0) {
370		keep_connections = TRUE;
371	}
372
373	if (!pid_file)
374		pid_file = strdup((read_config_file(configFile, PIDFILE_KEYWORD,
375					tmp) > 0) ? tmp : PIDFILE_DEFAULT);
376
377	if (!pptp_delegate) {
378		/* NOTE: remote then local, reason can be seen at the end of processIPStr */
379
380		/* grab the remoteip string from the config file */
381		if (read_config_file(configFile, REMOTEIP_KEYWORD, tmp) <= 0) {
382			/* use "smart" defaults */
383			strlcpy(tmp, DEFAULT_REMOTE_IP_LIST, sizeof(tmp));
384		}
385		processIPStr(REMOTE, tmp);
386
387		/* grab the localip string from the config file */
388		if (read_config_file(configFile, LOCALIP_KEYWORD, tmp) <= 0) {
389			/* use "smart" defaults */
390			strlcpy(tmp, DEFAULT_LOCAL_IP_LIST, sizeof(tmp));
391		}
392		processIPStr(LOCAL, tmp);
393	}
394
395	free(configFile);
396
397	/* if not yet set, adopt default PPP binary path */
398	if (!ppp_binary) ppp_binary = strdup(PPP_BINARY);
399	/* check that the PPP binary is executable */
400	if (access(ppp_binary, X_OK) < 0) {
401		syslog(LOG_ERR, "MGR: PPP binary %s not executable",
402		       ppp_binary);
403		return 1;
404	}
405	/* check that the PPP options file is readable */
406	if (pppdoptstr && access(pppdoptstr, R_OK) < 0) {
407		syslog(LOG_ERR, "MGR: PPP options file %s not readable",
408		       pppdoptstr);
409		return 1;
410	}
411#ifdef BCRELAY
412	/* check that the bcrelay binary is executable */
413	if (bcrelay && access(BCRELAY_BIN, X_OK) < 0) {
414		syslog(LOG_ERR, "MGR: bcrelay binary %s not executable",
415		       BCRELAY_BIN);
416		return 1;
417	}
418#endif
419
420	syslog(LOG_INFO, "accel-pptpd-%s compiled for pppd-%s, linux-%s\n",VERSION,PPPD_VERSION,KERNELVERSION);
421
422	if (!foreground) {
423#if HAVE_DAEMON
424		closelog();
425		freopen("/dev/null", "r", stdin);
426		daemon(0, 0);
427		/* returns to child only */
428		/* pid will have changed */
429		openlog("pptpd", LOG_PID, PPTP_FACILITY);
430#else	/* !HAVE_DAEMON */
431		my_daemon(argc, argv);
432		/* returns to child if !HAVE_FORK
433		 * never returns if HAVE_FORK (re-execs with -f)
434		 */
435#endif
436	}
437
438#ifdef BCRELAY
439      if (bcrelay) {
440             syslog(LOG_DEBUG, "CTRL: BCrelay incoming interface is %s", bcrelay);
441             /* Launch BCrelay  */
442#ifndef HAVE_FORK
443             switch(bcrelayfork = vfork()){
444#else
445             switch(bcrelayfork = fork()){
446#endif
447             case -1:        /* fork() error */
448                   syslog(LOG_ERR, "CTRL: Error forking to exec bcrelay");
449                   _exit(1);
450
451             case 0:         /* child */
452                   syslog(LOG_DEBUG, "CTRL (BCrelay Launcher): Launching BCrelay with pid %i", bcrelayfork);
453                   launch_bcrelay();
454                   syslog(LOG_ERR, "CTRL (BCrelay Launcher): Failed to launch BCrelay.");
455                   _exit(1);
456             }
457       } /* End bcrelay */
458#endif
459
460#ifdef CONFIG_NETtel
461	/* turn the NETtel VPN LED on */
462	ledman_cmd(LEDMAN_CMD_ON, LEDMAN_VPN);
463#endif
464	/* after we have our final pid... */
465	log_pid(pid_file);
466
467	/* manage connections until SIGTERM */
468	pptp_manager(argc, argv);
469
470#ifdef BCRELAY
471	if (bcrelayfork > 0) {
472		syslog(LOG_DEBUG, "CTRL: Closing child BCrelay with pid %i", bcrelayfork);
473		kill(bcrelayfork, SIGTERM);
474	}
475#endif
476
477	slot_free();
478	return 0;
479}
480
481static void log_pid(char *pid_file) {
482        FILE    *f;
483        pid_t   pid;
484
485        pid = getpid();
486        if ((f = fopen(pid_file, "w")) == NULL) {
487                syslog(LOG_ERR, "PPTPD: failed to open(%s), errno=%d\n",
488                        pid_file, errno);
489                return;
490        }
491        fprintf(f, "%d\n", pid);
492        fclose(f);
493}
494
495#ifndef HAVE_DAEMON
496static void my_daemon(int argc, char **argv)
497{
498#ifndef HAVE_FORK
499	/* need to use vfork - eg, uClinux */
500	char **new_argv;
501	int pid;
502	extern char **environ;
503	int fdr;
504
505	new_argv = malloc((argc + 2) * sizeof(char **));
506	fdr = open("/dev/null", O_RDONLY);
507	syslog(LOG_INFO, "MGR: Option parse OK, re-execing as daemon");
508	fflush(stderr);
509	if ((pid = vfork()) == 0) {
510		if (fdr != 0) { dup2(fdr, 0); close(fdr); }
511		SETSIDPGRP();
512		chdir("/");
513		umask(0);
514		memcpy(new_argv + 1, argv, (argc + 1) * sizeof(char **));
515		new_argv[0] = PPTPD_BIN;
516		new_argv[1] = "-f";
517		execve(PPTPD_BIN, new_argv, environ);
518		_exit(1);
519	} else if (pid > 0) {
520		exit(0);
521	} else {
522		syslog_perror("vfork");
523		exit(1);
524	}
525#else
526	int pid;
527
528	closelog();
529	if ((pid = fork()) < 0) {
530		syslog_perror("fork");
531		exit(1);
532	} else if (pid)
533		exit(0);
534	freopen("/dev/null", "r", stdin);
535	SETSIDPGRP();
536	chdir("/");
537	umask(0);
538	/* pid will have changed */
539	openlog("pptpd", LOG_PID, PPTP_FACILITY);
540#endif
541}
542#endif
543
544/* added for hostname/address lookup    -tmk
545 * returns NULL if not a valid hostname
546 */
547static char *lookup(char *hostname)
548{
549	struct hostent *ent;
550	struct in_addr hst_addr;
551
552	/* Try to parse IP directly */
553	if (inet_addr(hostname) != -1)
554		return hostname;
555
556	/* Else lookup hostname, return NULL if it fails */
557	if ((ent = gethostbyname(hostname)) == NULL)
558		return NULL;
559
560	/* That worked, print it back as a dotted quad. */
561	memcpy(&hst_addr.s_addr, ent->h_addr, ent->h_length);
562	return inet_ntoa(hst_addr);
563}
564
565#define DEBUG_IP_PARSER 0
566
567/* Return the address or NULL if not valid */
568static char *validip(char *hostname)
569{
570	/* Try to parse IP directly */
571	if (inet_addr(hostname) != -1)
572		return hostname;
573	else
574		return NULL;
575}
576
577/* Check if it's a valid IP range */
578static int isIpRange(char *str)
579{
580	int dashes = 0;
581	int dots = 0;
582
583#if DEBUG_IP_PARSER
584	syslog(LOG_DEBUG, "MGR: Checking if %s is a valid IP range", str);
585#endif
586	do {
587		if (*str == '-')
588			dashes++;
589		else if (*str == '.')
590			dots++;
591		else if (!strchr("0123456789", *str)) {
592#if DEBUG_IP_PARSER
593			syslog(LOG_DEBUG, "MGR: Not an IP range: character %c is not valid", *str);
594#endif
595			return 0;
596		}
597	} while (*++str);
598#if DEBUG_IP_PARSER
599	syslog(LOG_DEBUG, "MGR: Dashes = %d (wanted: 1), Dots = %d (wanted: 4)", dashes, dots);
600#endif
601	return (dashes == 1 && dots == 3);
602}
603
604/* process a type 0 (LOCAL) or type 1 (REMOTE) IP string */
605static void processIPStr(int type, char *ipstr)
606{
607	int pos;
608
609	char *tmpstr;
610	/* char tmpstr2[20]; xxx.xxx.xxx.xxx-xxx (largest we can get) */
611	char tmpstr2[128];	/* allow hostnames */
612	char *tmpstr3;
613	char tmpstr5[16];
614	char *tmpstr6;
615	char *tmpstr7;
616	int num;
617
618	char ipa[8];		/* xxx-xxx (largest we can get) */
619	char ipb[8];
620	char ipc[8];
621	char ipd[8];
622
623	char ip_pre[13];	/* xxx.xxx.xxx. (largest we can get) */
624	char ip_post[13];
625
626	char ipl[4];
627	char ipu[4];
628
629	int bail = FALSE;	/* so we know when to stop formatting the ip line */
630
631	int lower, upper, n;
632
633	num = 0;
634
635	while (!bail) {
636		if ((tmpstr = strchr(ipstr, ',')) == NULL) {
637			/* last (or only) entry reached */
638			strlcpy(tmpstr2, ipstr, sizeof(tmpstr2));
639			bail = TRUE;
640		} else {
641			pos = tmpstr - ipstr;
642			ipstr[pos] = '\0';
643			strlcpy(tmpstr2, ipstr, sizeof(tmpstr2));
644			ipstr = tmpstr + 1;
645		}
646
647#if DEBUG_IP_PARSER
648		syslog(LOG_DEBUG, "MGR: Parsing segment: %s", tmpstr2);
649#endif
650
651		if (!isIpRange(tmpstr2)) {
652			/* We got a normal IP
653			 * Check if the IP address is valid, use it if so
654			 */
655			if ((tmpstr7 = lookup(tmpstr2)) == NULL) {
656				syslog(LOG_ERR, "MGR: Bad IP address (%s) in config file!", tmpstr2);
657				exit(1);
658			}
659			if (num == pptp_connections) {
660				syslog(LOG_WARNING, "MGR: connections limit (%d) reached, extra IP addresses ignored", pptp_connections);
661				return;
662			}
663#if DEBUG_IP_PARSER
664			syslog(LOG_DEBUG, "MGR: Setting IP %d = %s", num, tmpstr7);
665#endif
666			if (type == LOCAL)
667				slot_set_local(num, tmpstr7);
668			else
669				slot_set_remote(num, tmpstr7);
670			num++;
671		} else {
672			/* Got a range;
673			 * eg. 192.168.0.234-238
674			 * or (thanx Kev! :-).. i thought i was finished :-)
675			 * 192.168-178.1.231
676			 */
677
678			/* lose the "."'s */
679			while ((tmpstr3 = strchr(tmpstr2, '.')) != NULL) {
680				pos = tmpstr3 - tmpstr2;
681				tmpstr2[pos] = ' ';
682			}
683
684			if ((tmpstr3 = strchr(tmpstr2, '-')) == NULL ||
685			    strchr(tmpstr3 + 1, '-') != NULL) {
686				syslog(LOG_ERR, "MGR: Confused in IP parse routines (multiple hyphens)");
687				continue;
688			}
689			/* should be left with "192 168 0 234-238"
690			 * or 192 168-178 1 231
691			 */
692
693			sscanf(tmpstr2, "%7s %7s %7s %7s", ipa, ipb, ipc, ipd);
694
695			if ((tmpstr6 = strchr(ipd, '-')) != NULL) {
696				pos = tmpstr6 - ipd;
697				ipd[pos] = ' ';
698				sscanf(ipd, "%3s %3s", ipl, ipu);
699#if DEBUG_IP_PARSER
700				syslog(LOG_DEBUG, "MGR: (lower upper) = (%s %s)", ipl, ipu);
701#endif
702				lower = atoi(ipl);
703				upper = atoi(ipu);
704#if DEBUG_IP_PARSER
705				syslog(LOG_DEBUG, "MGR: Range = %d to %d on 4th segment", lower, upper);
706#endif
707				sprintf(ip_pre, "%.3s.%.3s.%.3s.", ipa, ipb, ipc);
708				ip_post[0] = '\0';
709#if DEBUG_IP_PARSER
710				syslog(LOG_DEBUG, "MGR: Pre = %s Post = %s", ip_pre, ip_post);
711#endif
712			} else if ((tmpstr6 = strchr(ipc, '-')) != NULL) {
713				pos = tmpstr6 - ipc;
714				ipc[pos] = ' ';
715				sscanf(ipc, "%3s %3s", ipl, ipu);
716#if DEBUG_IP_PARSER
717				syslog(LOG_DEBUG, "MGR: (lower upper) = (%s %s)", ipl, ipu);
718#endif
719				lower = atoi(ipl);
720				upper = atoi(ipu);
721#if DEBUG_IP_PARSER
722				syslog(LOG_DEBUG, "MGR: Range = %d to %d on 3rd segment", lower, upper);
723#endif
724				sprintf(ip_pre, "%.3s.%.3s.", ipa, ipb);
725				sprintf(ip_post, ".%.3s", ipd);
726#if DEBUG_IP_PARSER
727				syslog(LOG_DEBUG, "MGR: Pre = %s Post = %s", ip_pre, ip_post);
728#endif
729			} else if ((tmpstr6 = strchr(ipb, '-')) != NULL) {
730				pos = tmpstr6 - ipb;
731				ipb[pos] = ' ';
732				sscanf(ipb, "%3s %3s", ipl, ipu);
733#if DEBUG_IP_PARSER
734				syslog(LOG_DEBUG, "MGR: (lower upper) = (%s %s)", ipl, ipu);
735#endif
736				lower = atoi(ipl);
737				upper = atoi(ipu);
738#if DEBUG_IP_PARSER
739				syslog(LOG_DEBUG, "MGR: Range = %d to %d on 2nd segment", lower, upper);
740#endif
741				sprintf(ip_pre, "%.3s.", ipa);
742				sprintf(ip_post, ".%.3s.%.3s", ipc, ipd);
743#if DEBUG_IP_PARSER
744				syslog(LOG_DEBUG, "MGR: Pre = %s Post = %s", ip_pre, ip_post);
745#endif
746			} else if ((tmpstr6 = strchr(ipa, '-')) != NULL) {
747				pos = tmpstr6 - ipa;
748				ipa[pos] = ' ';
749				sscanf(ipa, "%3s %3s", ipl, ipu);
750#if DEBUG_IP_PARSER
751				syslog(LOG_DEBUG, "MGR: (lower upper) = (%s %s)", ipl, ipu);
752#endif
753				lower = atoi(ipl);
754				upper = atoi(ipu);
755#if DEBUG_IP_PARSER
756				syslog(LOG_DEBUG, "MGR: Range = %d to %d on 1st segment", lower, upper);
757#endif
758				ip_pre[0] = '\0';
759				sprintf(ip_post, ".%.3s.%.3s.%.3s", ipb, ipc, ipd);
760#if DEBUG_IP_PARSER
761				syslog(LOG_DEBUG, "MGR: Pre = %s Post = %s", ip_pre, ip_post);
762#endif
763			} else {
764				syslog(LOG_ERR, "MGR: Confused in IP parse routines (lost hyphen)");
765				continue;
766			}
767
768			for (n = lower; n <= upper; n++) {
769				sprintf(tmpstr5, "%s%d%s", ip_pre, n, ip_post);
770				/* Check if the ip address is valid */
771				if ((tmpstr7 = validip(tmpstr5)) == NULL) {
772					syslog(LOG_ERR, "MGR: Bad IP address (%s) in config file!", tmpstr5);
773					exit(1);
774				}
775				if (num == pptp_connections) {
776					syslog(LOG_WARNING, "MGR: connections limit (%d) reached, extra IP addresses ignored", pptp_connections);
777					return;
778				}
779#if DEBUG_IP_PARSER
780				syslog(LOG_DEBUG, "MGR: Setting IP %d = %s", num, tmpstr7);
781#endif
782				if (type == LOCAL)
783					slot_set_local(num, tmpstr7);
784				else
785					slot_set_remote(num, tmpstr7);
786				num++;
787			}
788		}
789	}
790	if (num == 1 && type == LOCAL && pptp_connections > 1) {
791#if DEBUG_IP_PARSER
792		syslog(LOG_DEBUG, "MGR: Setting all %d local IPs to %s", pptp_connections, slot_get_local(0));
793#endif
794		for (n = 1; n < pptp_connections; n++)
795			slot_set_local(n, slot_get_local(0));
796	} else if (pptp_connections > num) {
797		syslog(LOG_INFO, "MGR: Maximum of %d connections reduced to %d, not enough IP addresses given",
798		       pptp_connections, num);
799		pptp_connections = num;
800	}
801}
802
803#ifdef BCRELAY
804/* launch_bcrelay
805 * Launches broadcast relay. Broadcast relay is responsible for relaying broadcasts to the clients
806 * retn: 0 on success, -1 on failure.
807 */
808static void launch_bcrelay() {
809  char *bcrelay_argv[8];
810  int an = 0;
811
812      if (bcrelay) {
813	   char *outif = strchr(bcrelay, ',');
814	   if (outif == NULL)
815	         outif = "ppp[0-9].*";
816	   else *outif++ = '\0';
817
818           syslog(LOG_DEBUG, "MGR: BCrelay incoming interface is %s", bcrelay);
819           syslog(LOG_DEBUG, "MGR: BCrelay outgoing interface is regexp %s", outif);
820
821	   bcrelay_argv[an++] = BCRELAY_BIN;
822	   bcrelay_argv[an++] = "-i";
823	   bcrelay_argv[an++] = bcrelay;
824	   bcrelay_argv[an++] = "-o";
825	   bcrelay_argv[an++] = outif;
826           if (!pptp_debug) {
827	         bcrelay_argv[an++] = "-n";
828           }
829	   bcrelay_argv[an++] = NULL;
830
831           execvp(bcrelay_argv[0], bcrelay_argv);
832      }
833}
834#endif
835