1/*
2 * pptpctrl.c
3 *
4 * PPTP control connection between PAC-PNS pair
5 *
6 * $Id: pptpctrl.c,v 1.19 2005/10/30 22:40:41 quozl Exp $
7 *
8 * 24.02.2008 Bugs fixed by Serbulov D. (SDY)
9 *  + added SIGCHLD control
10 *  + added PPPD kill on stop ses
11 *  + correct exit on duplicate connection
12 *
13 */
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#ifdef __linux__
20#define _GNU_SOURCE 1		/* kill() prototype, broken arpa/inet.h */
21#endif
22
23#include "our_syslog.h"
24
25#include <fcntl.h>
26#include <errno.h>
27#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <time.h>
33#include <sys/time.h>
34#include <dirent.h>
35#include <sys/types.h>
36#include <sys/wait.h>
37#include <sys/socket.h>
38#include <sys/ioctl.h>
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#ifdef HAVE_OPENPTY
42#ifdef HAVE_PTY_H
43#include <pty.h>
44#endif
45#ifdef HAVE_LIBUTIL_H
46#include <libutil.h>
47#endif
48#endif
49
50#ifdef __UCLIBC__
51#define socklen_t int
52#endif
53
54#include "compat.h"
55#include "pptpctrl.h"
56#include "pptpdefs.h"
57#include "ctrlpacket.h"
58#include "defaults.h"
59// placing net/if.h here fixes build on Solaris
60#include <net/if.h>
61#include <net/ethernet.h>
62//#include "if_pppox.h" //Yau del
63#include <linux/if_pppox.h>
64
65static char *ppp_binary = PPP_BINARY;
66static int pptp_logwtmp;
67static int noipparam;			/* if true, don't send ipparam to ppp */
68static char speed[32];
69static char pppdxfig[256];
70static pid_t pppfork;                   /* so we can kill it after disconnect */
71
72/*
73 * Global to handle dying
74 *
75 * I'd be nice if someone could figure out a way to do it
76 * without the global, but i don't think you can.. -tmk
77 */
78#define clientSocket 0		/* in case it changes back to a variable */
79static u_int32_t call_id_pair;	/* call id (to terminate call) */
80int window=10;
81int pptp_sock=-1;
82struct in_addr inetaddrs[2];
83
84/* Needed by this and ctrlpacket.c */
85int pptpctrl_debug = 0;		/* specifies if debugging is on or off */
86uint16_t unique_call_id = 0xFFFF;	/* Start value for our call IDs on this TCP link */
87int pptp_timeout=1000000;
88
89int gargc;                     /* Command line argument count */
90char **gargv;                  /* Command line argument vector */
91
92/* Local function prototypes */
93static void bail(int sigraised);
94static void pptp_handle_ctrl_connection(char **pppaddrs, struct in_addr *inetaddrs);
95
96static int startCall(char **pppaddrs, struct in_addr *inetaddrs);
97static void launch_pppd(char **pppaddrs, struct in_addr *inetaddrs);
98
99/* Oh the horror.. lets hope this covers all the ones we have to handle */
100#if defined(O_NONBLOCK) && !defined(__sun__) && !defined(__sun)
101#define OUR_NB_MODE O_NONBLOCK
102#else
103#define OUR_NB_MODE O_NDELAY
104#endif
105
106/* read a command line argument, a flag alone */
107#define GETARG_INT(X) \
108	X = atoi(argv[arg++])
109
110/* read a command line argument, a string alone */
111#define GETARG_STRING(X) \
112	X = strdup(argv[arg++])
113
114/* read a command line argument, a presence flag followed by string */
115#define GETARG_VALUE(X) \
116	if(atoi(argv[arg++]) != 0) \
117		strlcpy(X, argv[arg++], sizeof(X)); \
118	else \
119		*X = '\0'
120
121int main(int argc, char **argv)
122{
123	char pppLocal[16];		/* local IP to pass to pppd */
124	char pppRemote[16];		/* remote IP address to pass to pppd */
125	struct sockaddr_in addr;	/* client address */
126	socklen_t addrlen;
127	int arg = 1;
128	int flags;
129	char *pppaddrs[2] = { pppLocal, pppRemote };
130
131        gargc = argc;
132        gargv = argv;
133
134	/* fail if argument count invalid */
135	if (argc < 7) {
136		fprintf(stderr, "pptpctrl: insufficient arguments, see man pptpctrl\n");
137		exit(2);
138	}
139
140	/* open a connection to the syslog daemon */
141	openlog("pptpd", LOG_PID, PPTP_FACILITY);
142
143	/* autoreap if supported */
144	signal(SIGCHLD, SIG_IGN);
145
146	/* note: update pptpctrl.8 if the argument list format is changed */
147	GETARG_INT(pptpctrl_debug);
148	GETARG_INT(noipparam);
149	GETARG_VALUE(pppdxfig);
150	GETARG_VALUE(speed);
151	GETARG_VALUE(pppLocal);
152	GETARG_VALUE(pppRemote);
153	if (arg < argc) GETARG_INT(pptp_timeout);
154	if (arg < argc) GETARG_STRING(ppp_binary);
155	if (arg < argc) GETARG_INT(pptp_logwtmp);
156
157	if (pptpctrl_debug) {
158		if (*pppLocal)
159			syslog(LOG_DEBUG, "CTRL: local address = %s", pppLocal);
160		if (*pppRemote)
161			syslog(LOG_DEBUG, "CTRL: remote address = %s", pppRemote);
162		if (*speed)
163			syslog(LOG_DEBUG, "CTRL: pppd speed = %s", speed);
164		if (*pppdxfig)
165			syslog(LOG_DEBUG, "CTRL: pppd options file = %s", pppdxfig);
166	}
167
168	addrlen = sizeof(addr);
169	if (getsockname(clientSocket, (struct sockaddr *) &addr, &addrlen) != 0) {
170		syslog(LOG_ERR, "CTRL: getsockname() failed");
171		syslog_perror("getsockname");
172		close(clientSocket);
173		bail(0);	/* NORETURN */
174	}
175	inetaddrs[0] = addr.sin_addr;
176
177	addrlen = sizeof(addr);
178	if (getpeername(clientSocket, (struct sockaddr *) &addr, &addrlen) != 0) {
179		syslog(LOG_ERR, "CTRL: getpeername() failed");
180		syslog_perror("getpeername");
181		close(clientSocket);
182		bail(0);	/* NORETURN */
183	}
184	inetaddrs[1] = addr.sin_addr;
185
186	/* Set non-blocking */
187	if ((flags = fcntl(clientSocket, F_GETFL, arg /* ignored */)) == -1 ||
188	    fcntl(clientSocket, F_SETFL, flags|OUR_NB_MODE) == -1) {
189		syslog(LOG_ERR, "CTRL: Failed to set client socket non-blocking");
190		syslog_perror("fcntl");
191		close(clientSocket);
192		bail(0);	/* NORETURN */
193	}
194
195
196	/* Fiddle with argv */
197        my_setproctitle(gargc, gargv, "pptpd [%s]%20c",
198            inet_ntoa(addr.sin_addr), ' ');
199
200	/* be ready for a grisly death */
201	sigpipe_create();
202	sigpipe_assign(SIGCHLD);
203	sigpipe_assign(SIGTERM);
204	NOTE_VALUE(PAC, call_id_pair, htons(-1));
205	NOTE_VALUE(PNS, call_id_pair, htons(-1));
206
207	syslog(LOG_INFO, "CTRL: Client %s control connection started", inet_ntoa(addr.sin_addr));
208	pptp_handle_ctrl_connection(pppaddrs, inetaddrs);
209
210	syslog(LOG_DEBUG, "CTRL: Reaping child PPP[%i]", pppfork);
211	bail(0);		/* NORETURN */
212	syslog(LOG_INFO, "CTRL: Client %s control connection finished", inet_ntoa(addr.sin_addr));
213	return 1;		/* make gcc happy */
214}
215
216//SDY special for prevent pppd session stay on air then need to stop
217void waitclosefork(int sigraised)
218{
219	//SDY senf term to fork();
220	if (pppfork > 0)
221	{
222		if (sigraised != SIGCHLD) {
223			syslog(LOG_INFO, "CTRL: Client pppd TERM sending");
224			kill(pppfork,SIGTERM);
225		}
226		syslog(LOG_INFO, "CTRL: Client pppd finish wait");
227		waitpid(pppfork, NULL, 0);
228	}
229}
230
231/*
232 * Local functions only below
233 */
234
235/*
236 * pptp_handle_ctrl_connection
237 *
238 * 1. read a packet (should be start_ctrl_conn_rqst)
239 * 2. reply to packet (send a start_ctrl_conn_rply)
240 * 3. proceed with GRE and CTRL connections
241 *
242 * args: pppaddrs - ppp local and remote addresses (strings)
243 *       inetaddrs - local and client socket address
244 * retn: 0 success, -1 failure
245 */
246static void pptp_handle_ctrl_connection(char **pppaddrs, struct in_addr *inetaddrs)
247{
248
249	/* For echo requests used to check link is alive */
250	int echo_wait = FALSE;		/* Waiting for echo? */
251	u_int32_t echo_count = 0;	/* Sequence # of echo */
252	time_t echo_time = 0;		/* Time last echo req sent */
253	struct timeval idleTime;	/* How long to select() */
254
255	/* General local variables */
256	ssize_t rply_size;		/* Reply packet size */
257	fd_set fds;			/* For select() */
258	int maxfd = clientSocket;	/* For select() */
259	int send_packet;		/* Send a packet this time? */
260#if BSDUSER_PPP || SLIRP
261/* not needed by stuff which uses socketpair() in startCall() */
262#define init 1
263#else
264	int init = 0;			/* Has pppd initialized the pty? */
265#endif
266	int sig_fd = sigpipe_fd();	/* Signal pipe descriptor	*/
267
268	unsigned char packet[PPTP_MAX_CTRL_PCKT_SIZE];
269	unsigned char rply_packet[PPTP_MAX_CTRL_PCKT_SIZE];
270
271	struct sockaddr_pppox dst_addr;
272
273	for (;;) {
274
275		FD_ZERO(&fds);
276		FD_SET(sig_fd, &fds);
277		FD_SET(clientSocket, &fds);
278
279		/* set timeout */
280		idleTime.tv_sec = IDLE_WAIT;
281			idleTime.tv_usec = 0;
282
283		/* default: do nothing */
284		send_packet = FALSE;
285
286		switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
287		case -1:	/* Error with select() */
288			if (errno != EINTR)
289				syslog(LOG_ERR, "CTRL: Error with select(), quitting");
290			goto leave_clear_call;
291
292		case 0:
293			if (echo_wait != TRUE) {
294				/* Timeout. Start idle link detection. */
295				echo_count++;
296				if (pptpctrl_debug)
297					syslog(LOG_DEBUG, "CTRL: Sending ECHO REQ id %d", echo_count);
298				time(&echo_time);
299				make_echo_req_packet(rply_packet, &rply_size, echo_count);
300				echo_wait = TRUE;
301				send_packet = TRUE;
302			}
303			break;
304
305		default:
306			break;
307		}
308
309		/* check for pending SIGTERM delivery */
310		if (FD_ISSET(sig_fd, &fds)) {
311			int signum = sigpipe_read();
312			if (signum == SIGCHLD)
313				bail(SIGCHLD);
314			else if (signum == SIGTERM)
315				bail(SIGTERM);
316		}
317
318		/* handle control messages */
319
320		if (FD_ISSET(clientSocket, &fds)) {
321			send_packet = TRUE;
322			switch (read_pptp_packet(clientSocket, packet, rply_packet, &rply_size)) {
323			case 0:
324				syslog(LOG_ERR, "CTRL: CTRL read failed");
325				goto leave_drop_call;
326
327			case -1:
328				send_packet = FALSE;
329				break;
330
331			case STOP_CTRL_CONN_RQST:
332				if (pptpctrl_debug)
333					syslog(LOG_DEBUG, "CTRL: Received STOP CTRL CONN request (disconnecting)");
334				send_pptp_packet(clientSocket, rply_packet, rply_size);
335				goto leave_drop_call;
336
337			case CALL_CLR_RQST:
338				if(pptpctrl_debug)
339					syslog(LOG_DEBUG, "CTRL: Received CALL CLR request (closing call)");
340				/* violating RFC */
341                                goto leave_drop_call;
342
343			case OUT_CALL_RQST:
344				/* for killing off the link later (ugly) */
345				NOTE_VALUE(PAC, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id);
346				NOTE_VALUE(PNS, call_id_pair, ((struct pptp_out_call_rply *) (rply_packet))->call_id_peer);
347
348				dst_addr.sa_family=AF_PPPOX;
349				dst_addr.sa_protocol=PX_PROTO_PPTP;
350				dst_addr.sa_addr.pptp.call_id=htons(((struct pptp_out_call_rply *) (rply_packet))->call_id_peer);
351				dst_addr.sa_addr.pptp.sin_addr=inetaddrs[1];
352
353				if (connect(pptp_sock,(struct sockaddr*)&dst_addr,sizeof(dst_addr))){
354					syslog(LOG_INFO,"CTRL: failed to connect PPTP socket (%s)\n",strerror(errno));
355					goto leave_drop_call; //SDY close on correct!
356					break;
357				}
358
359
360                                /* change process title for accounting and status scripts */
361                                my_setproctitle(gargc, gargv,
362                                      "pptpd [%s:%04X - %04X]",
363                                      inet_ntoa(inetaddrs[1]),
364                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id_peer),
365                                      ntohs(((struct pptp_out_call_rply *) (rply_packet))->call_id));
366				/* start the call, by launching pppd */
367				syslog(LOG_INFO, "CTRL: Starting call (launching pppd, opening GRE)");
368				startCall(pppaddrs, inetaddrs);
369				close(pptp_sock);
370				pptp_sock=-1;
371				break;
372
373			case ECHO_RPLY:
374				if (echo_wait == TRUE && ((struct pptp_echo_rply *) (packet))->identifier == echo_count)
375					echo_wait = FALSE;
376				else
377					syslog(LOG_WARNING, "CTRL: Unexpected ECHO REPLY packet");
378				/* FALLTHRU */
379			case SET_LINK_INFO:
380				send_packet = FALSE;
381				break;
382
383#ifdef PNS_MODE
384			case IN_CALL_RQST:
385			case IN_CALL_RPLY:
386			case IN_CALL_CONN:
387#endif
388
389			case CALL_DISCONN_NTFY:
390			case STOP_CTRL_CONN_RPLY:
391				/* These don't generate replies.  Also they come from things we don't send in this section. */
392				syslog(LOG_WARNING, "CTRL: Got a reply to a packet we didn't send");
393				send_packet = FALSE;
394				break;
395
396			/* Otherwise, the already-formed reply will do fine, so send it */
397			}
398		}
399
400		/* send reply packet - this may block, but it should be very rare */
401		if (send_packet == TRUE && send_pptp_packet(clientSocket, rply_packet, rply_size) < 0) {
402			syslog(LOG_ERR, "CTRL: Error sending GRE, aborting call");
403			goto leave_clear_call;
404		}
405
406		/* waiting for echo reply and curtime - echo_time > max wait */
407		if (echo_wait == TRUE && (time(NULL) - echo_time) > MAX_ECHO_WAIT) {
408			syslog(LOG_INFO, "CTRL: Session timed out, ending call");
409			goto leave_clear_call;
410		}
411	}
412	/* Finished! :-) */
413leave_drop_call:
414	NOTE_VALUE(PAC, call_id_pair, htons(-1));
415	NOTE_VALUE(PNS, call_id_pair, htons(-1));
416	close(clientSocket);
417leave_clear_call:
418	return;
419#ifdef init
420#undef init
421#endif
422}
423
424
425/*
426 * This is the custom exit() for this program.
427 *
428 * Updated to also be the default SIGTERM handler, and if
429 * the link is going down for unnatural reasons, we will close it
430 * right now, it's only been tested for win98, other tests would be nice
431 * -tmk
432 */
433static void bail(int sigraised)
434{
435	if (sigraised)
436		syslog(LOG_INFO, "CTRL: Exiting on signal %d", sigraised);
437
438	waitclosefork(sigraised);
439
440	/* send a disconnect to the other end */
441	/* ignore any errors */
442	if (GET_VALUE(PAC, call_id_pair) != htons(-1)) {
443		fd_set connSet;		/* fd_set for select() */
444		struct timeval tv;	/* time to wait for reply */
445		unsigned char packet[PPTP_MAX_CTRL_PCKT_SIZE];
446		unsigned char rply_packet[PPTP_MAX_CTRL_PCKT_SIZE];
447		ssize_t rply_size;	/* reply packet size */
448		int pkt;
449		int retry = 0;
450
451		if (pptpctrl_debug)
452			syslog(LOG_DEBUG, "CTRL: Exiting with active call");
453
454		make_call_admin_shutdown(rply_packet, &rply_size);
455		if(send_pptp_packet(clientSocket, rply_packet, rply_size) < 0)
456			goto skip;
457
458		make_stop_ctrl_req(rply_packet, &rply_size);
459		if(send_pptp_packet(clientSocket, rply_packet, rply_size) < 0)
460			goto skip;
461
462		FD_ZERO(&connSet);
463		FD_SET(clientSocket, &connSet);
464		tv.tv_sec = 5;	/* wait 5 secs for a reply then quit */
465		tv.tv_usec = 0;
466
467		/* Wait for STOP CTRL CONN RQST or RPLY */
468		while (select(clientSocket + 1, &connSet, NULL, NULL, &tv) == 1) {
469			switch((pkt = read_pptp_packet(clientSocket, packet, rply_packet, &rply_size))) {
470			case STOP_CTRL_CONN_RQST:
471				send_pptp_packet(clientSocket, rply_packet, rply_size);
472				goto skip;
473			case CALL_CLR_RQST:
474				syslog(LOG_WARNING, "CTRL: Got call clear request after call manually shutdown - buggy client");
475				break;
476			case STOP_CTRL_CONN_RPLY:
477				goto skip;
478			case -1:
479				syslog(LOG_WARNING, "CTRL: Retryable error in disconnect sequence");
480				retry++;
481				break;
482			case 0:
483				syslog(LOG_WARNING, "CTRL: Fatal error reading control message in disconnect sequence");
484				goto skip;
485			default:
486				syslog(LOG_WARNING, "CTRL: Unexpected control message %d in disconnect sequence", pkt);
487				retry++;
488				break;
489			}
490			tv.tv_sec = 5;	/* wait 5 secs for another reply then quit */
491			tv.tv_usec = 0;
492			if (retry > 100) {
493				syslog(LOG_WARNING, "CTRL: Too many retries (%d) - giving up", retry);
494				break;
495			}
496		}
497
498	skip:
499		NOTE_VALUE(PAC, call_id_pair, htons(-1));
500		NOTE_VALUE(PNS, call_id_pair, htons(-1));
501		close(clientSocket);
502	}
503
504	if (pptpctrl_debug)
505		syslog(LOG_DEBUG, "CTRL: Exiting now");
506}
507
508/*
509 * startCall
510 *
511 * Launches PPPD for the call.
512 *
513 * args:        pppaddrs - local/remote IPs or "" for either/both if none
514 * retn:        pty file descriptor
515 *
516 */
517static int startCall(char **pppaddrs, struct in_addr *inetaddrs)
518{
519	/* Launch the PPPD  */
520#ifndef HAVE_FORK
521        switch(pppfork=vfork()){
522#else
523        switch(pppfork=fork()){
524#endif
525	case -1:	/* fork() error */
526		syslog(LOG_ERR, "CTRL: Error forking to exec pppd");
527		_exit(1);
528
529	case 0:		/* child */
530/* In case we move clientSocket back off stdin */
531#ifndef clientSocket
532		if (clientSocket > 1)
533			close(clientSocket);
534#elif clientSocket > 1
535		close(clientSocket);
536#endif
537		launch_pppd(pppaddrs, inetaddrs);
538		syslog(LOG_ERR, "CTRL: PPPD launch failed! (launch_pppd did not fork)");
539		_exit(1);
540	}
541
542	return -1;
543}
544
545/*
546 * launch_pppd
547 *
548 * Launches the PPP daemon. The PPP daemon is responsible for assigning the
549 * PPTP client its IP address.. These values are assigned via the command
550 * line.
551 *
552 * Add return of connected ppp interface
553 *
554 * retn: 0 on success, -1 on failure.
555 *
556 */
557static void launch_pppd(char **pppaddrs, struct in_addr *inetaddrs)
558{
559	char *pppd_argv[25];
560	int an = 0;
561	sigset_t sigs;
562	char tmp[128];
563
564	pppd_argv[an++] = ppp_binary;
565
566	if (pptpctrl_debug) {
567		syslog(LOG_DEBUG,
568		       "CTRL (PPPD Launcher): program binary = %s",
569		       pppd_argv[an - 1]);
570	}
571
572#if BSDUSER_PPP
573
574	/* The way that Brian Somers' user-land ppp works is to use the
575	 * system name as a reference for most of the useful options. Hence
576	 * most things can't be defined on the command line. On OpenBSD at
577	 * least the file used for the systems is /etc/ppp/ppp.conf, where
578	 * the pptp stanza should look something like:
579
580	 pptp:
581	 set speed sync
582	 enable pap
583	 enable chap
584	 set dns a.a.a.a b.b.b.b
585	 set ndbs x.x.x.x y.y.y.y
586	 accept dns
587	 add 10.0.0/24
588
589	 * To be honest, at the time of writing, I haven't had the thing
590	 * working enough to understand :) I will update this comment and
591	 * make a sample config available when I get there.
592	 */
593
594	/* options for BSDUSER_PPP
595	 *
596	 * ignores IP addresses, config file option, speed
597	 * fix usage info in pptpd.c and configure script if this changes
598	 *
599	 * IP addresses can be specified in /etc/ppp/ppp.secret per user
600	 */
601	pppd_argv[an++] = "-direct";
602	pppd_argv[an++] = "pptp";	/* XXX this is the system name */
603	/* should be dynamic - PMG */
604
605#elif SLIRP
606
607	/* options for SLIRP
608	 *
609	 * ignores IP addresses from config - SLIRP handles this
610	 */
611	pppd_argv[an++] = "-P";
612	pppd_argv[an++] = "+chap";
613	pppd_argv[an++] = "-b";
614
615	/* If a speed has been specified, use it
616	 * if not, use "smart" default (defaults.h)
617	 */
618	if (*speed) {
619		pppd_argv[an++] = speed;
620	} else {
621		pppd_argv[an++] = PPP_SPEED_DEFAULT;
622	}
623
624	if (*pppdxfig) {
625		pppd_argv[an++] = "-f";
626		pppd_argv[an++] = pppdxfig;
627	}
628
629	if (pptpctrl_debug) {
630		syslog(LOG_DEBUG, "CTRL (PPPD Launcher): Connection speed = %s", pppd_argv[an - 1]);
631	}
632#else
633
634	/* options for 'normal' pppd */
635
636	pppd_argv[an++] = "local";
637
638	/* If a pppd option file is specified, use it
639	 * if not, pppd will default to /etc/ppp/options
640	 */
641	if (*pppdxfig) {
642		pppd_argv[an++] = "file";
643		pppd_argv[an++] = pppdxfig;
644	}
645
646	/* If a speed has been specified, use it
647	 * if not, use "smart" default (defaults.h)
648	 */
649	if (*speed) {
650		pppd_argv[an++] = speed;
651	} else {
652		pppd_argv[an++] = PPP_SPEED_DEFAULT;
653	}
654
655	if (pptpctrl_debug) {
656		if (*pppaddrs[0])
657			syslog(LOG_DEBUG, "CTRL (PPPD Launcher): local address = %s", pppaddrs[0]);
658		if (*pppaddrs[1])
659			syslog(LOG_DEBUG, "CTRL (PPPD Launcher): remote address = %s", pppaddrs[1]);
660	}
661
662	if (*pppaddrs[0] || *pppaddrs[1]) {
663		char pppInterfaceIPs[33];
664		sprintf(pppInterfaceIPs, "%s:%s", pppaddrs[0], pppaddrs[1]);
665		pppd_argv[an++] = pppInterfaceIPs;
666	}
667#endif
668
669        if (!noipparam) {
670                 pppd_argv[an++] = "ipparam";
671                 pppd_argv[an++] = inet_ntoa(inetaddrs[1]);
672        }
673
674        if (pptp_logwtmp) {
675                 pppd_argv[an++] = "plugin";
676                 pppd_argv[an++] = "/usr/lib/pptpd/pptpd-logwtmp.so";
677                 pppd_argv[an++] = "pptpd-original-ip";
678                 pppd_argv[an++] = inet_ntoa(inetaddrs[1]);
679        }
680
681	pppd_argv[an++] = "plugin";
682	pppd_argv[an++] = "pptp.so";
683	pppd_argv[an++] = "pptp_client";
684	strcpy(tmp,inet_ntoa(inetaddrs[1]));
685	pppd_argv[an++] = strdup(tmp);
686	pppd_argv[an++] = "pptp_sock";
687	sprintf(tmp,"%u",pptp_sock);
688	pppd_argv[an++] = strdup(tmp);
689	pppd_argv[an++] = "nodetach";
690
691	/* argv arrays must always be NULL terminated */
692	pppd_argv[an++] = NULL;
693	/* make sure SIGCHLD is unblocked, pppd does not expect it */
694	sigfillset(&sigs);
695	sigprocmask(SIG_UNBLOCK, &sigs, NULL);
696	/* run pppd now */
697	execvp(pppd_argv[0], pppd_argv);
698	/* execvp() failed */
699	syslog(LOG_ERR,
700	       "CTRL (PPPD Launcher): Failed to launch PPP daemon. %s",
701	       strerror(errno));
702}
703