1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * main.c - Point-to-Point Protocol main module
25 *
26 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 *
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in
37 *    the documentation and/or other materials provided with the
38 *    distribution.
39 *
40 * 3. The name "Carnegie Mellon University" must not be used to
41 *    endorse or promote products derived from this software without
42 *    prior written permission. For permission or any legal
43 *    details, please contact
44 *      Office of Technology Transfer
45 *      Carnegie Mellon University
46 *      5000 Forbes Avenue
47 *      Pittsburgh, PA  15213-3890
48 *      (412) 268-4387, fax: (412) 268-7395
49 *      tech-transfer@andrew.cmu.edu
50 *
51 * 4. Redistributions of any form whatsoever must retain the following
52 *    acknowledgment:
53 *    "This product includes software developed by Computing Services
54 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
55 *
56 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
57 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
58 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
59 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
60 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
61 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
62 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
63 */
64
65#define RCSID	"$Id: main.c,v 1.34.20.1 2006/04/17 18:37:15 callie Exp $"
66
67#include <stdio.h>
68#include <ctype.h>
69#include <stdlib.h>
70#include <string.h>
71#include <unistd.h>
72#include <signal.h>
73#include <errno.h>
74#include <fcntl.h>
75#include <syslog.h>
76#include <netdb.h>
77#include <pwd.h>
78#include <setjmp.h>
79#include <sys/param.h>
80#include <sys/types.h>
81#include <sys/wait.h>
82#include <sys/time.h>
83#include <sys/resource.h>
84#include <sys/stat.h>
85#include <sys/socket.h>
86#include <pthread.h>
87#include <netinet/in.h>
88#include <arpa/inet.h>
89
90#include "scnc_utils_common.h"
91
92#include "pppd.h"
93#include "magic.h"
94#include "fsm.h"
95#include "lcp.h"
96#include "ipcp.h"
97#ifdef INET6
98#include "ipv6cp.h"
99#endif
100#ifdef ACSCP
101#include "acscp.h"
102#endif
103#include "upap.h"
104#include "chap-new.h"
105#include "eap.h"
106#include "ccp.h"
107#include "ecp.h"
108#include "pathnames.h"
109
110#ifdef USE_TDB
111#include "tdb.h"
112#endif
113
114#ifdef CBCP_SUPPORT
115#include "cbcp.h"
116#endif
117
118#ifdef IPX_CHANGE
119#include "ipxcp.h"
120#endif /* IPX_CHANGE */
121#ifdef AT_CHANGE
122#include "atcp.h"
123#endif
124
125#ifndef lint
126static const char rcsid[] = RCSID;
127#endif
128
129/* interface vars */
130char ifname[32];		/* Interface name */
131int ifunit;			/* Interface unit number */
132
133struct channel *the_channel;
134
135char *progname;			/* Name of this program */
136char hostname[MAXNAMELEN];	/* Our hostname */
137static char pidfilename[MAXPATHLEN];	/* name of pid file */
138static char linkpidfile[MAXPATHLEN];	/* name of linkname pid file */
139char ppp_devnam[MAXPATHLEN];	/* name of PPP tty (maybe ttypx) */
140uid_t uid;			/* Our real user-id */
141struct notifier *pidchange = NULL;
142struct notifier *phasechange = NULL;
143struct notifier *exitnotify = NULL;
144struct notifier *sigreceived = NULL;
145struct notifier *fork_notifier = NULL;
146struct notifier *protocolsready_notifier = NULL;
147struct notifier *acspdhcpready_notifier = NULL;
148
149int hungup;			/* terminal has been hung up */
150int do_modem_hungup;			/* need to finish disconnection */
151int privileged;			/* we're running as real uid root */
152int need_holdoff;		/* need holdoff period before restarting */
153int detached;			/* have detached from terminal */
154volatile int status;		/* exit status for pppd */
155#ifdef __APPLE__
156volatile int devstatus;		/* exit device status for pppd */
157#endif
158int unsuccess;			/* # unsuccessful connection attempts */
159int do_callback;		/* != 0 if we should do callback next */
160int doing_callback;		/* != 0 if we are doing callback */
161int ppp_session_number;		/* Session number, for channels with such a
162				   concept (eg PPPoE) */
163#ifdef USE_TDB
164TDB_CONTEXT *pppdb;		/* database for storing status etc. */
165#endif
166
167char db_key[32];
168
169int (*holdoff_hook) __P((void)) = NULL;
170int (*new_phase_hook) __P((int)) = NULL;
171void (*snoop_recv_hook) __P((unsigned char *p, int len)) = NULL;
172void (*snoop_send_hook) __P((unsigned char *p, int len)) = NULL;
173
174static int conn_running;	/* we have a [dis]connector running */
175static int devfd;		/* fd of underlying device */
176static int fd_ppp = -1;		/* fd for talking PPP */
177static int fd_loop;		/* fd for getting demand-dial packets */
178static int fd_devnull;		/* fd for /dev/null */
179
180int phase;			/* where the link is at */
181int kill_link;
182int open_ccp_flag;
183int listen_time;
184int got_sigusr2;
185int got_sigterm;
186int got_sighup;
187#ifdef __APPLE__
188int stop_link;
189int cont_link;
190int got_sigtstp;
191int got_sigcont;
192#endif
193
194static int waiting;
195static sigjmp_buf sigjmp;
196
197char **script_env;		/* Env. variable values for scripts */
198int s_env_nalloc;		/* # words avail at script_env */
199
200/*
201 *  WCast-align fix - these buffers need to be aligned so that (after the 4 byte ppp header is removed)
202 *  the protocol handling routines such as acsp can expect that the data is aligned on a 4 byte boundary
203 */
204u_char outpacket_buf[PPP_MRU+PPP_HDRLEN] __attribute__ ((aligned (4))); /* buffer for outgoing packet */
205u_char inpacket_buf[PPP_MRU+PPP_HDRLEN] __attribute__ ((aligned (4))); /* buffer for incoming packet */
206
207static int n_children;		/* # child processes still running */
208static int got_sigchld;		/* set if we have received a SIGCHLD */
209
210int privopen;			/* don't lock, open device as root */
211
212char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
213
214GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */
215int ngroups;			/* How many groups valid in groups */
216
217static struct timeval start_time;	/* Time when link was started. */
218
219struct pppd_stats link_stats;
220unsigned link_connect_time;
221int link_stats_valid;
222
223int error_count;
224
225/*
226 * We maintain a list of child process pids and
227 * functions to call when they exit.
228 */
229struct subprocess {
230    pid_t	pid;
231    char	*prog;
232    void	(*done) __P((void *));
233    void	*arg;
234    struct subprocess *next;
235};
236
237static struct subprocess *children;
238
239#ifdef __APPLE__
240static pthread_t mainthread_id = NULL;
241#endif
242
243/* Prototypes for procedures local to this file. */
244
245static void setup_signals __P((void));
246static void create_pidfile __P((int pid));
247static void create_linkpidfile __P((int pid));
248static void cleanup __P((void));
249static void get_input __P((void));
250static void calltimeout __P((void));
251static struct timeval *timeleft __P((struct timeval *));
252static void kill_my_pg __P((int));
253static void hup __P((int));
254#ifdef __APPLE__
255static void stop __P((int));
256static void cont __P((int));
257#endif
258static void term __P((int));
259static void chld __P((int));
260static void toggle_debug __P((int));
261static void open_ccp __P((int));
262static void bad_signal __P((int));
263static void holdoff_end __P((void *));
264static int reap_kids __P((int waitfor));
265
266#ifdef USE_TDB
267static void update_db_entry __P((void));
268static void add_db_key __P((const char *));
269static void delete_db_key __P((const char *));
270static void cleanup_db __P((void));
271#endif
272
273static void handle_events __P((void));
274static void print_link_stats __P((void));
275
276extern	char	*ttyname __P((int));
277extern	char	*getlogin __P((void));
278int main __P((int, char *[]));
279
280#ifdef __APPLE__
281void (*wait_input_hook) __P((void)) = NULL;
282int (*start_link_hook) __P((void))		= NULL;
283int (*link_up_hook) __P((void))			= NULL;
284bool link_up_done = 0;
285int (*terminal_window_hook) __P((char *, int, int)) 	= NULL;
286int  redialingcount = 0;
287bool  redialingalternate = 0;
288struct notifier *connect_started_notify = NULL;
289struct notifier *connect_success_notify = NULL;
290struct notifier *connect_fail_notify = NULL;
291struct notifier *disconnect_started_notify = NULL;
292struct notifier *disconnect_done_notify = NULL;
293struct notifier *stop_notify = NULL;
294struct notifier *cont_notify = NULL;
295struct notifier *system_inited_notify = NULL;
296struct notifier *network_probed_notify = NULL;
297int wait_underlying_interface_up = 0;
298int retry_pre_start_link_check = 0;
299#endif
300
301#ifdef ultrix
302#undef	O_NONBLOCK
303#define	O_NONBLOCK	O_NDELAY
304#endif
305
306#ifdef ULTRIX
307#define setlogmask(x)
308#endif
309
310
311/*
312 * PPP Data Link Layer "protocol" table.
313 * One entry per supported protocol.
314 * The last entry must be NULL.
315 */
316struct protent *protocols[] = {
317    &lcp_protent,
318    &pap_protent,
319    &chap_protent,
320#ifdef CBCP_SUPPORT
321    &cbcp_protent,
322#endif
323    &ipcp_protent,
324#ifdef INET6
325    &ipv6cp_protent,
326#endif
327#ifdef ACSCP
328    &acscp_protent,
329#endif
330    &ccp_protent,
331    &ecp_protent,
332#ifdef IPX_CHANGE
333    &ipxcp_protent,
334#endif
335#ifdef AT_CHANGE
336    &atcp_protent,
337#endif
338    &eap_protent,
339    NULL
340};
341
342/*
343 * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name.
344 */
345#if !defined(PPP_DRV_NAME)
346#define PPP_DRV_NAME	"ppp"
347#endif /* !defined(PPP_DRV_NAME) */
348
349int
350main(argc, argv)
351    int argc;
352    char *argv[];
353{
354    int i, t = 0;
355    char *p;
356    struct passwd *pw;
357    struct protent *protp;
358    char numbuf[16];
359
360    /* Initialize syslog facilities */
361    reopen_log();
362
363
364#ifdef __APPLE__
365    mainthread_id = pthread_self();
366#endif
367    link_stats_valid = 0;
368    new_phase(PHASE_INITIALIZE);
369
370
371    script_env = NULL;
372
373    if (gethostname(hostname, MAXNAMELEN) < 0 ) {
374	option_error("Couldn't get hostname: %m");
375	exit(1);
376    }
377    hostname[MAXNAMELEN-1] = 0;
378
379    /* make sure we don't create world or group writable files. */
380    umask(umask(0777) | 022);
381
382    uid = getuid();
383    privileged = uid == 0;
384#ifdef __APPLE__
385	if (!privileged)
386		privileged = sys_check_controller();
387#endif
388    slprintf(numbuf, sizeof(numbuf), "%d", uid);
389    script_setenv("ORIG_UID", numbuf, 0);
390
391    ngroups = getgroups(NGROUPS_MAX, groups);
392
393    /*
394     * Initialize magic number generator now so that protocols may
395     * use magic numbers in initialization.
396     */
397    magic_init();
398
399    /*
400     * Initialize each protocol.
401     */
402    for (i = 0; (protp = protocols[i]) != NULL; ++i)
403        (*protp->init)(0);
404
405    /*
406     * Initialize the default channel.
407     */
408    tty_init();
409
410    progname = *argv;
411
412#ifdef __APPLE__
413    sys_install_options();
414#endif
415
416    /*
417     * Parse, in order, the system options file, the user's options file,
418     * and the command line arguments.
419     */
420    if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
421	|| !options_from_user()
422	|| !parse_args(argc-1, argv+1)
423#ifdef __APPLE__
424	|| ((controlled) && !options_from_controller())
425        // options file to add additionnal parameters, after the plugins are loaded
426        // should not be used, except for debugging purpose, or specific behavior override
427        // anything set there will override what is specified as argument by the PPPController
428        // so only the admin should use it...
429    	|| !options_from_file(_PATH_SYSPOSTOPTIONS, 0, 0, 1)
430#endif
431        )
432	exit(EXIT_OPTION_ERROR);
433    devnam_fixed = 1;		/* can no longer change device name */
434
435    /*
436     * Work out the device name, if it hasn't already been specified,
437     * and parse the tty's options file.
438     */
439    if (the_channel->process_extra_options)
440	(*the_channel->process_extra_options)();
441
442    if (debug)
443	setlogmask(LOG_UPTO(LOG_DEBUG));
444
445    /*
446     * Check that we are running as root.
447     */
448    if (geteuid() != 0) {
449	option_error("must be root to run %s, since it is not setuid-root",
450		     argv[0]);
451	exit(EXIT_NOT_ROOT);
452    }
453
454    if (!ppp_available()) {
455	option_error("%s", no_ppp_msg);
456	exit(EXIT_NO_KERNEL_SUPPORT);
457    }
458
459    /*
460     * Check that the options given are valid and consistent.
461     */
462    check_options();
463    if (!sys_check_options())
464	exit(EXIT_OPTION_ERROR);
465    auth_check_options();
466#ifdef HAVE_MULTILINK
467    mp_check_options();
468#endif
469    for (i = 0; (protp = protocols[i]) != NULL; ++i)
470	if (protp->check_options != NULL)
471	    (*protp->check_options)();
472    if (the_channel->check_options)
473	(*the_channel->check_options)();
474
475    if (dump_options || dryrun) {
476	init_pr_log(NULL, LOG_INFO);
477	print_options(pr_log, NULL);
478	end_pr_log();
479    }
480
481    if (dryrun)
482	die(0);
483
484    /*
485     * Initialize system-dependent stuff.
486     */
487    sys_init();
488#ifdef __APPLE__
489	notify(system_inited_notify, 0);
490#endif
491
492
493    /* Make sure fds 0, 1, 2 are open to somewhere. */
494    fd_devnull = open(_PATH_DEVNULL, O_RDWR);
495    if (fd_devnull < 0)
496	fatal("Couldn't open %s: %m", _PATH_DEVNULL);
497    while (fd_devnull <= 2) {
498	i = dup(fd_devnull);
499	if (i < 0)
500	    fatal("Critical shortage of file descriptors: dup failed: %m");
501	fd_devnull = i;
502    }
503
504#ifdef USE_TDB
505    pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644);
506    if (pppdb != NULL) {
507	slprintf(db_key, sizeof(db_key), "pppd%d", getpid());
508	update_db_entry();
509    } else {
510	warning("Warning: couldn't open ppp database %s", _PATH_PPPDB);
511	if (multilink) {
512	    warning("Warning: disabling multilink");
513	    multilink = 0;
514	}
515    }
516#endif
517
518    /*
519     * Detach ourselves from the terminal, if required,
520     * and identify who is running us.
521     */
522    if (!nodetach && !updetach)
523	detach();
524#ifndef __APPLE__
525	// radar 6153490
526	p = getlogin();
527    if (p == NULL) {
528#endif
529	pw = getpwuid(uid);
530	if (pw != NULL && pw->pw_name != NULL)
531	    p = pw->pw_name;
532	else
533	    p = "(unknown)";
534#ifndef __APPLE__
535    }
536#endif
537#ifdef __APPLE__
538    syslog(LOG_NOTICE, "pppd %s (Apple version %s) started by %s, uid %d", VERSION, PPP_VERSION,  p, uid);
539#else
540    syslog(LOG_NOTICE, "pppd %s started by %s, uid %d", VERSION, p, uid);
541#endif
542    script_setenv("PPPLOGNAME", p, 0);
543
544    if (devnam[0])
545	script_setenv("DEVICE", devnam, 1);
546    slprintf(numbuf, sizeof(numbuf), "%d", getpid());
547    script_setenv("PPPD_PID", numbuf, 1);
548
549#if __APPLE__
550    if (controlfd !=-1)
551        add_fd(controlfd);
552#endif
553
554    setup_signals();
555
556    waiting = 0;
557
558    /*
559     * If we're doing dial-on-demand, set up the interface now.
560     */
561    if (demand) {
562	/*
563	 * Open the loopback channel and set it up to be the ppp interface.
564	 */
565#ifdef USE_TDB
566	tdb_writelock(pppdb);
567#endif
568	fd_loop = open_ppp_loopback();
569	set_ifunit(1);
570#ifdef USE_TDB
571	tdb_writeunlock(pppdb);
572#endif
573	/*
574	 * Configure the interface and mark it up, etc.
575	 */
576	demand_conf();
577	create_linkpidfile(getpid());
578    }
579
580#ifdef __APPLE__
581	if (holdfirst) {
582		need_holdoff = 1;
583		goto hold;
584	}
585#endif
586
587    do_callback = 0;
588    for (;;) {
589
590	listen_time = 0;
591	need_holdoff = 1;
592	devfd = -1;
593	status = EXIT_OK;
594#ifdef __APPLE__
595	devstatus = 0;
596#endif
597	++unsuccess;
598	doing_callback = do_callback;
599	do_callback = 0;
600
601	if (demand && !doing_callback) {
602	    /*
603	     * Don't do anything until we see some activity.
604	     */
605	    new_phase(PHASE_DORMANT);
606	    demand_unblock();
607	    add_fd(fd_loop);
608	    for (;;) {
609		handle_events();
610		if (kill_link && !persist)
611		    break;
612		if (get_loop_output())
613		    break;
614	    }
615	    remove_fd(fd_loop);
616	    if (kill_link && !persist)
617		break;
618
619	    /*
620	     * Now we want to bring up the link.
621	     */
622	    demand_block();
623	    info("Starting link");
624	}
625
626#ifdef __APPLE__
627        if (start_link_hook) {
628            if (the_channel->pre_start_link_check) {
629                int rc = -1;
630                if (retry_pre_start_link_check < 0)
631                    retry_pre_start_link_check = 0;
632                for (i = 1 + retry_pre_start_link_check; i > 0; i--) {
633                    if (!(rc = the_channel->pre_start_link_check())) {
634                        break;
635                    }
636                }
637                if (rc) {
638                    status = EXIT_PEER_UNREACHABLE;
639                    goto end;
640                }
641            }
642
643            t = (*start_link_hook)();
644            if (t == 0) {
645               // cancelled
646                status = EXIT_USER_REQUEST;
647                goto end;
648            }
649        }
650#endif
651
652#ifdef __APPLE__
653	sys_publish_remoteaddress(remoteaddress);
654#endif
655	new_phase(PHASE_SERIALCONN);
656
657#ifdef __APPLE__
658    notify(connect_started_notify, 0);
659    link_up_done = 0;
660    redialingcount = 0;
661    redialingalternate = 0;
662    do {
663        if (redialingcount || redialingalternate) {
664            if (the_channel->cleanup)
665                (*the_channel->cleanup)();
666            if (redialalternate)
667                sys_publish_remoteaddress(redialingalternate ? altremoteaddress : remoteaddress);
668        }
669
670        if (redialtimer && redialingcount && !redialingalternate) {
671            if (hasbusystate)
672				new_phase(PHASE_WAITONBUSY);
673            sleep(redialtimer);
674            if (hasbusystate)
675				new_phase(PHASE_SERIALCONN);
676        }
677        if (kill_link)
678			break;
679	devfd = the_channel->connect(&t);
680
681        if (redialalternate)
682            redialingalternate = !redialingalternate;
683        if (!redialingalternate)
684            redialingcount++;
685    }
686    while ((busycode != -1) && (t == busycode) && (redialingcount <= redialcount) && !kill_link);
687#else
688	devfd = the_channel->connect();
689#endif
690	if (devfd < 0) {
691#ifdef __APPLE__
692            if (devfd == -2) {
693                if (conn_running)
694                    /* Send the signal to the [dis]connector process(es) also */
695                    kill_my_pg(SIGHUP);
696                goto disconnect;
697            }
698            else {
699                notify(connect_fail_notify, t);
700#endif
701	    goto fail;
702#ifdef __APPLE__
703            }
704#endif
705    }
706#ifdef __APPLE__
707        /*
708            link_up_done is there to give a chance to a device to implement
709            a double step connection.
710            For example, the serial connection will call directly link_up_hook
711            between the connection script and terminal script.
712            The link_up_hook hook can be used to ask for a password, that
713            could be used by a terminal script
714        */
715        if (!link_up_done) {
716            if (link_up_hook) {
717                t = (*link_up_hook)();
718                if (t == 0) {
719                    // cancelled
720                    status = EXIT_USER_REQUEST;
721                    goto disconnect;
722                }
723            }
724            link_up_done = 1;
725        }
726        notify(connect_success_notify, 0);
727#endif
728
729#ifdef __APPLE__
730        /* republish the remote address in case the connector has changed it */
731	sys_publish_remoteaddress(remoteaddress);
732#endif
733
734	/* set up the serial device as a ppp interface */
735#ifdef USE_TDB
736	tdb_writelock(pppdb);
737#endif
738	fd_ppp = the_channel->establish_ppp(devfd);
739	if (fd_ppp < 0) {
740#ifdef USE_TDB
741	    tdb_writeunlock(pppdb);
742#endif
743	    status = EXIT_FATAL_ERROR;
744	    goto disconnect;
745	}
746	/* create the pid file, now that we've obtained a ppp interface */
747	if (!demand)
748	    create_linkpidfile(getpid());
749
750	if (!demand && ifunit >= 0)
751	    set_ifunit(1);
752#ifdef USE_TDB
753	tdb_writeunlock(pppdb);
754#endif
755
756	/*
757	 * Start opening the connection and wait for
758	 * incoming events (reply, timeout, etc.).
759	 */
760	if (ifunit >= 0)
761		notice("Connect: %s <--> %s", ifname, ppp_devnam);
762	else
763		notice("Starting negotiation on %s", ppp_devnam);
764	gettimeofday(&start_time, NULL);
765	script_unsetenv("CONNECT_TIME");
766	script_unsetenv("BYTES_SENT");
767	script_unsetenv("BYTES_RCVD");
768	lcp_lowerup(0);
769
770	add_fd(fd_ppp);
771	lcp_open(0);		/* Start protocol */
772	status = EXIT_NEGOTIATION_FAILED;
773	new_phase(PHASE_ESTABLISH);
774	while (phase != PHASE_DEAD) {
775		handle_events();
776	    get_input();
777#ifdef __APPLE__
778            if (stop_link) {
779                if (phase == PHASE_RUNNING) {
780                    new_phase(PHASE_ONHOLD);
781                    ppp_hold(0);
782                    auth_hold(0);
783                    for (i = 0; (protp = protocols[i]) != NULL; ++i)
784                        if (protp->hold != NULL)
785                            (*protp->hold)(0);
786                    notify(stop_notify, 0);
787                }
788            }
789            if (cont_link) {
790                if (phase == PHASE_ONHOLD) {
791                    new_phase(PHASE_RUNNING);
792                    ppp_cont(0);
793                    auth_cont(0);
794                    for (i = 0; (protp = protocols[i]) != NULL; ++i)
795                        if (protp->cont != NULL)
796                            (*protp->cont)(0);
797                    notify(cont_notify, 0);
798                }
799            }
800#endif
801	    if (kill_link) {
802#ifdef __APPLE__
803                if (do_modem_hungup || stop_link || phase == PHASE_ONHOLD) {
804					if (do_modem_hungup) {
805						notice("Modem hangup");
806						do_modem_hungup = 0;
807					}
808                    hungup = 1;
809                    lcp_lowerdown(0);
810                    link_terminated(0);
811                }
812#endif
813		lcp_close(0, "User request");
814            }
815	    if (open_ccp_flag) {
816		if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
817		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
818		    (*ccp_protent.open)(0);
819		}
820	    }
821#ifdef __APPLE__
822		sys_runloop();
823#endif
824	}
825
826	print_link_stats();
827
828	/*
829	 * Delete pid file before disestablishing ppp.  Otherwise it
830	 * can happen that another pppd gets the same unit and then
831	 * we delete its pid file.
832	 */
833	if (!demand) {
834	    if (pidfilename[0] != 0
835		&& unlink(pidfilename) < 0 && errno != ENOENT)
836		warning("unable to delete pid file %s: %m", pidfilename);
837	    pidfilename[0] = 0;
838	}
839
840	/*
841	 * If we may want to bring the link up again, transfer
842	 * the ppp unit back to the loopback.  Set the
843	 * real serial device back to its normal mode of operation.
844	 */
845	remove_fd(fd_ppp);
846	clean_check();
847	the_channel->disestablish_ppp(devfd);
848	fd_ppp = -1;
849	if (!hungup)
850	    lcp_lowerdown(0);
851	if (!demand)
852	    script_unsetenv("IFNAME");
853
854	/*
855	 * Run disconnector script, if requested.
856	 * XXX we may not be able to do this if the line has hung up!
857	 */
858    disconnect:
859	new_phase(PHASE_DISCONNECT);
860#ifdef __APPLE__
861        notify(disconnect_started_notify, status);
862#endif
863	if (the_channel->disconnect)
864	    the_channel->disconnect();
865#ifdef __APPLE__
866        notify(disconnect_done_notify, status);
867#endif
868    fail:
869#ifdef __APPLE__
870    if (phase != PHASE_DISCONNECT)
871        new_phase(PHASE_DISCONNECT);
872#endif
873	if (the_channel->cleanup)
874	    (*the_channel->cleanup)();
875#ifdef __APPLE__
876    end:
877#endif
878#ifdef __APPLE__
879        sys_statusnotify();
880#endif
881
882	if (!demand) {
883	    if (pidfilename[0] != 0
884		&& unlink(pidfilename) < 0 && errno != ENOENT)
885		warning("unable to delete pid file %s: %m", pidfilename);
886	    pidfilename[0] = 0;
887	}
888
889	if (!persist || (maxfail > 0 && unsuccess >= maxfail))
890	    break;
891
892	if (demand)
893	    demand_discard();
894#ifdef __APPLE__
895	hold:
896#endif
897	t = need_holdoff? holdoff: 0;
898	if (holdoff_hook)
899	    t = (*holdoff_hook)();
900	if (t > 0) {
901	    new_phase(PHASE_HOLDOFF);
902	    TIMEOUT(holdoff_end, NULL, t);
903		/* clear kill_link related signal flags */
904		got_sighup = got_sigterm = 0;
905	    do {
906		handle_events();
907		if (kill_link) {
908		    new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
909		}
910	    } while (phase == PHASE_HOLDOFF);
911	    if (!persist)
912		break;
913	}
914    }
915
916    /* Wait for scripts to finish */
917    /* XXX should have a timeout here */
918    while (n_children > 0) {
919	if (debug) {
920	    struct subprocess *chp;
921	    dbglog("Waiting for %d child processes...", n_children);
922	    for (chp = children; chp != NULL; chp = chp->next)
923		dbglog("  script %s, pid %d", chp->prog, chp->pid);
924	}
925	if (reap_kids(1) < 0)
926	    break;
927    }
928
929    die(status);
930    return 0;
931}
932
933/*
934 * control fron controller - Read a string of commandd from controller file descriptor,
935 * and interpret them.
936 */
937void
938ppp_control()
939{
940    int newline, c, flags;
941    char cmd[MAXWORDLEN];
942
943    /* set the file descriptor in non blocking mode */
944    flags = fcntl(controlfd, F_GETFL);
945    if (flags == -1
946        || fcntl(controlfd, F_SETFL, flags | O_NONBLOCK) == -1) {
947        warning("Couldn't set controlfd to nonblock: %m");
948        return;
949    }
950    /* skip chars until beginning of next command */
951    for (;;) {
952	c = getc(controlfile);
953	if (c == EOF)
954	    break;
955        if (c == '[')
956            ungetc(c, controlfile);
957            break;
958    }
959    /* reset blocking mode */
960    fcntl(controlfd, F_SETFL, flags);
961
962    /* we get eof if controller exits */
963    if (feof(controlfile))
964        die(1);
965
966    /* clear error */
967    clearerr(controlfile);
968
969    if (c != '[')
970        return;
971
972    /* now ready to read the command */
973    while (getword(controlfile, cmd, &newline, "controller")) {
974
975        if (!strcmp(cmd, "[OPTIONS]")) {
976            options_from_controller();
977            if (dump_options) {
978                init_pr_log(NULL, LOG_INFO);
979                print_options(pr_log, NULL);
980                end_pr_log();
981            }
982            return;
983        }
984
985        if (!strcmp(cmd, "[DISCONNECT]")) {
986            error("[DISCONNECT]");
987            hup(SIGHUP);
988            continue;
989        }
990
991        if (!strcmp(cmd, "[TERMINATE]")) {
992            error("[TERMINATE]");
993            term(SIGTERM);
994            continue;
995        }
996
997/*
998        if (!strcmp(cmd, "[SUSPEND]")) {
999            error("[SUSPEND]");
1000            stop(SIGTSTP);
1001            continue;
1002        }
1003
1004        if (!strcmp(cmd, "[RESUME]")) {
1005            error("[RESUME]");
1006            cont(SIGCONT);
1007            continue;
1008        }
1009*/
1010
1011        if (!strcmp(cmd, "[EOP]")) {
1012            break;
1013        }
1014
1015    }
1016
1017    // got EOF
1018    die(1);
1019}
1020
1021/*
1022 * handle_events - wait for something to happen and respond to it.
1023 */
1024static void
1025handle_events()
1026{
1027    struct timeval timo;
1028    sigset_t mask;
1029
1030
1031    kill_link = open_ccp_flag = 0;
1032#ifdef __APPLE__
1033    stop_link = cont_link = 0;
1034#endif
1035    if (sigsetjmp(sigjmp, 1) == 0) {
1036	sigprocmask(SIG_BLOCK, &mask, NULL);
1037	if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld
1038#ifdef __APPLE__
1039            || got_sigtstp || got_sigcont
1040#endif
1041            ) {
1042	    sigprocmask(SIG_UNBLOCK, &mask, NULL);
1043	} else {
1044	    waiting = 1;
1045	    sigprocmask(SIG_UNBLOCK, &mask, NULL);
1046	    wait_input(timeleft(&timo));
1047#ifdef __APPLE__
1048            if (wait_input_hook)
1049                (*wait_input_hook)();
1050            if (the_channel->wait_input)
1051                the_channel->wait_input();
1052#endif
1053	}
1054    }
1055#ifdef __APPLE__
1056    if (controlfd !=-1 && is_ready_fd(controlfd)) {
1057        ppp_control();
1058    }
1059#endif
1060    waiting = 0;
1061    calltimeout();
1062#ifdef __APPLE__
1063    if (got_sigtstp) {
1064		info("Stopping on signal %d.", got_sigtstp);
1065        stop_link = 1;
1066        got_sigtstp = 0;
1067    }
1068    if (got_sigcont) {
1069		info("Resuming on signal %d.", got_sigcont);
1070        cont_link = 1;
1071        got_sigcont = 0;
1072    }
1073#endif
1074    if (got_sighup) {
1075    info("Hangup (SIGHUP)");
1076	kill_link = 1;
1077	got_sighup = 0;
1078	if (status != EXIT_HANGUP)
1079	    status = EXIT_USER_REQUEST;
1080    }
1081    if (got_sigterm) {
1082    info("Terminating on signal %d.", got_sigterm);
1083	kill_link = 1;
1084	persist = 0;
1085	status = EXIT_USER_REQUEST;
1086	got_sigterm = 0;
1087    }
1088    if (got_sigchld) {
1089	reap_kids(0);	/* Don't leave dead kids lying around */
1090	got_sigchld = 0;
1091    }
1092    if (got_sigusr2) {
1093	open_ccp_flag = 1;
1094	got_sigusr2 = 0;
1095    }
1096}
1097
1098/*
1099 * setup_signals - initialize signal handling.
1100 */
1101static void
1102setup_signals()
1103{
1104    struct sigaction sa;
1105    sigset_t mask;
1106
1107    /*
1108     * Compute mask of all interesting signals and install signal handlers
1109     * for each.  Only one signal handler may be active at a time.  Therefore,
1110     * all other signals should be masked when any handler is executing.
1111     */
1112    sigemptyset(&mask);
1113    sigaddset(&mask, SIGHUP);
1114    sigaddset(&mask, SIGINT);
1115    sigaddset(&mask, SIGTERM);
1116    sigaddset(&mask, SIGCHLD);
1117    sigaddset(&mask, SIGUSR2);
1118#ifdef __APPLE__
1119    sigaddset(&mask, SIGTSTP);
1120    sigaddset(&mask, SIGCONT);
1121#endif
1122
1123#define SIGNAL(s, handler)	do { \
1124	sa.sa_handler = handler; \
1125	if (sigaction(s, &sa, NULL) < 0) \
1126	    fatal("Couldn't establish signal handler (%d): %m", s); \
1127    } while (0)
1128
1129    sa.sa_mask = mask;
1130    sa.sa_flags = 0;
1131    SIGNAL(SIGHUP, hup);		/* Hangup */
1132    SIGNAL(SIGINT, term);		/* Interrupt */
1133    SIGNAL(SIGTERM, term);		/* Terminate */
1134    SIGNAL(SIGCHLD, chld);
1135#ifdef __APPLE__
1136    SIGNAL(SIGTSTP, stop);		/* stop all activity */
1137    SIGNAL(SIGCONT, cont);		/* resume activity */
1138#endif
1139
1140    SIGNAL(SIGUSR1, toggle_debug);	/* Toggle debug flag */
1141    SIGNAL(SIGUSR2, open_ccp);		/* Reopen CCP */
1142
1143    /*
1144     * Install a handler for other signals which would otherwise
1145     * cause pppd to exit without cleaning up.
1146     */
1147    SIGNAL(SIGABRT, bad_signal);
1148    SIGNAL(SIGALRM, bad_signal);
1149    SIGNAL(SIGFPE, bad_signal);
1150    SIGNAL(SIGILL, bad_signal);
1151    SIGNAL(SIGPIPE, bad_signal);
1152    SIGNAL(SIGQUIT, bad_signal);
1153    SIGNAL(SIGSEGV, bad_signal);
1154#ifdef SIGBUS
1155    SIGNAL(SIGBUS, bad_signal);
1156#endif
1157#ifdef SIGEMT
1158    SIGNAL(SIGEMT, bad_signal);
1159#endif
1160#ifdef SIGPOLL
1161    SIGNAL(SIGPOLL, bad_signal);
1162#endif
1163#ifdef SIGPROF
1164    SIGNAL(SIGPROF, bad_signal);
1165#endif
1166#ifdef SIGSYS
1167    SIGNAL(SIGSYS, bad_signal);
1168#endif
1169#ifdef SIGTRAP
1170    SIGNAL(SIGTRAP, bad_signal);
1171#endif
1172#ifdef SIGVTALRM
1173    SIGNAL(SIGVTALRM, bad_signal);
1174#endif
1175#ifdef SIGXCPU
1176    SIGNAL(SIGXCPU, bad_signal);
1177#endif
1178#ifdef SIGXFSZ
1179    SIGNAL(SIGXFSZ, bad_signal);
1180#endif
1181
1182    /*
1183     * Apparently we can get a SIGPIPE when we call syslog, if
1184     * syslogd has died and been restarted.  Ignoring it seems
1185     * be sufficient.
1186     */
1187#ifndef __APPLE__
1188    signal(SIGPIPE, SIG_IGN);
1189#endif
1190}
1191
1192/*
1193 * set_ifunit - do things we need to do once we know which ppp
1194 * unit we are using.
1195 */
1196void
1197set_ifunit(iskey)
1198    int iskey;
1199{
1200    info("Using interface %s%d", PPP_DRV_NAME, ifunit);
1201    slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
1202    script_setenv("IFNAME", ifname, iskey);
1203    if (iskey) {
1204	create_pidfile(getpid());	/* write pid to file */
1205	create_linkpidfile(getpid());
1206    }
1207}
1208
1209/*
1210 * detach - detach us from the controlling terminal.
1211 */
1212void
1213detach()
1214{
1215    int pid;
1216    char numbuf[16];
1217    int pipefd[2];
1218
1219    if (detached)
1220	return;
1221    if (pipe(pipefd) == -1)
1222	pipefd[0] = pipefd[1] = -1;
1223    if ((pid = fork()) < 0) {
1224	error("Couldn't detach (fork failed: %m)");
1225	die(1);			/* or just return? */
1226    }
1227    if (pid != 0) {
1228	/* parent */
1229	notify(pidchange, pid);
1230	/* update pid files if they have been written already */
1231	if (pidfilename[0])
1232	    create_pidfile(pid);
1233	if (linkpidfile[0])
1234	    create_linkpidfile(pid);
1235	exit(0);		/* parent dies */
1236    }
1237    setsid();
1238    chdir("/");
1239    dup2(fd_devnull, 0);
1240    dup2(fd_devnull, 1);
1241    dup2(fd_devnull, 2);
1242    detached = 1;
1243    if (log_default)
1244	log_to_fd = -1;
1245    slprintf(numbuf, sizeof(numbuf), "%d", getpid());
1246    script_setenv("PPPD_PID", numbuf, 1);
1247
1248    /* wait for parent to finish updating pid & lock files and die */
1249    close(pipefd[1]);
1250    complete_read(pipefd[0], numbuf, 1);
1251    close(pipefd[0]);
1252
1253#ifdef __APPLE__
1254    sys_reinit();
1255#endif
1256}
1257
1258/*
1259 * reopen_log - (re)open our connection to syslog.
1260 */
1261void
1262reopen_log()
1263{
1264#ifdef ULTRIX
1265    openlog("pppd", LOG_PID);
1266#else
1267    openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
1268    setlogmask(LOG_UPTO(LOG_INFO));
1269#endif
1270}
1271
1272/*
1273 * Create a file containing our process ID.
1274 */
1275static void
1276create_pidfile(pid)
1277    int pid;
1278{
1279    FILE *pidfile;
1280
1281    slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid",
1282	     _PATH_VARRUN, ifname);
1283    if ((pidfile = fopen(pidfilename, "w")) != NULL) {
1284	fprintf(pidfile, "%d\n", pid);
1285	(void) fclose(pidfile);
1286    } else {
1287	error("Failed to create pid file %s: %m", pidfilename);
1288	pidfilename[0] = 0;
1289    }
1290}
1291
1292static void
1293create_linkpidfile(pid)
1294    int pid;
1295{
1296    FILE *pidfile;
1297
1298    if (linkname[0] == 0)
1299	return;
1300    script_setenv("LINKNAME", linkname, 1);
1301    slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid",
1302	     _PATH_VARRUN, linkname);
1303    if ((pidfile = fopen(linkpidfile, "w")) != NULL) {
1304	fprintf(pidfile, "%d\n", pid);
1305	if (ifname[0])
1306	    fprintf(pidfile, "%s\n", ifname);
1307	(void) fclose(pidfile);
1308    } else {
1309	error("Failed to create pid file %s: %m", linkpidfile);
1310	linkpidfile[0] = 0;
1311    }
1312}
1313
1314/*
1315 * holdoff_end - called via a timeout when the holdoff period ends.
1316 */
1317static void
1318holdoff_end(arg)
1319    void *arg;
1320{
1321    new_phase(PHASE_DORMANT);
1322}
1323
1324/* List of protocol names, to make our messages a little more informative. */
1325struct protocol_list {
1326    u_short	proto;
1327    const char	*name;
1328} protocol_list[] = {
1329    { 0x21,	"IP" },
1330    { 0x23,	"OSI Network Layer" },
1331    { 0x25,	"Xerox NS IDP" },
1332    { 0x27,	"DECnet Phase IV" },
1333    { 0x29,	"Appletalk" },
1334    { 0x2b,	"Novell IPX" },
1335    { 0x2d,	"VJ compressed TCP/IP" },
1336    { 0x2f,	"VJ uncompressed TCP/IP" },
1337    { 0x31,	"Bridging PDU" },
1338    { 0x33,	"Stream Protocol ST-II" },
1339    { 0x35,	"Banyan Vines" },
1340    { 0x39,	"AppleTalk EDDP" },
1341    { 0x3b,	"AppleTalk SmartBuffered" },
1342    { 0x3d,	"Multi-Link" },
1343    { 0x3f,	"NETBIOS Framing" },
1344    { 0x41,	"Cisco Systems" },
1345    { 0x43,	"Ascom Timeplex" },
1346    { 0x45,	"Fujitsu Link Backup and Load Balancing (LBLB)" },
1347    { 0x47,	"DCA Remote Lan" },
1348    { 0x49,	"Serial Data Transport Protocol (PPP-SDTP)" },
1349    { 0x4b,	"SNA over 802.2" },
1350    { 0x4d,	"SNA" },
1351    { 0x4f,	"IP6 Header Compression" },
1352    { 0x6f,	"Stampede Bridging" },
1353    { 0xfb,	"single-link compression" },
1354    { 0xfd,	"1st choice compression" },
1355    { 0x0201,	"802.1d Hello Packets" },
1356    { 0x0203,	"IBM Source Routing BPDU" },
1357    { 0x0205,	"DEC LANBridge100 Spanning Tree" },
1358    { 0x0231,	"Luxcom" },
1359    { 0x0233,	"Sigma Network Systems" },
1360    { 0x0235,	"Apple Client Server Protocol" },
1361    { 0x8021,	"Internet Protocol Control Protocol" },
1362    { 0x8023,	"OSI Network Layer Control Protocol" },
1363    { 0x8025,	"Xerox NS IDP Control Protocol" },
1364    { 0x8027,	"DECnet Phase IV Control Protocol" },
1365    { 0x8029,	"Appletalk Control Protocol" },
1366    { 0x802b,	"Novell IPX Control Protocol" },
1367    { 0x8031,	"Bridging NCP" },
1368    { 0x8033,	"Stream Protocol Control Protocol" },
1369    { 0x8035,	"Banyan Vines Control Protocol" },
1370    { 0x803d,	"Multi-Link Control Protocol" },
1371    { 0x803f,	"NETBIOS Framing Control Protocol" },
1372    { 0x8041,	"Cisco Systems Control Protocol" },
1373    { 0x8043,	"Ascom Timeplex" },
1374    { 0x8045,	"Fujitsu LBLB Control Protocol" },
1375    { 0x8047,	"DCA Remote Lan Network Control Protocol (RLNCP)" },
1376    { 0x8049,	"Serial Data Control Protocol (PPP-SDCP)" },
1377    { 0x804b,	"SNA over 802.2 Control Protocol" },
1378    { 0x804d,	"SNA Control Protocol" },
1379    { 0x804f,	"IP6 Header Compression Control Protocol" },
1380    { 0x006f,	"Stampede Bridging Control Protocol" },
1381    { 0x80fb,	"Single Link Compression Control Protocol" },
1382    { 0x80fd,	"Compression Control Protocol" },
1383    { 0x8235,	"Apple Client Server Control Protocol" },
1384    { 0xc021,	"Link Control Protocol" },
1385    { 0xc023,	"Password Authentication Protocol" },
1386    { 0xc025,	"Link Quality Report" },
1387    { 0xc027,	"Shiva Password Authentication Protocol" },
1388    { 0xc029,	"CallBack Control Protocol (CBCP)" },
1389    { 0xc081,	"Container Control Protocol" },
1390    { 0xc223,	"Challenge Handshake Authentication Protocol" },
1391    { 0xc281,	"Proprietary Authentication Protocol" },
1392    { 0,	NULL },
1393};
1394
1395/*
1396 * protocol_name - find a name for a PPP protocol.
1397 */
1398const char *
1399protocol_name(proto)
1400    int proto;
1401{
1402    struct protocol_list *lp;
1403
1404    for (lp = protocol_list; lp->proto != 0; ++lp)
1405	if (proto == lp->proto)
1406	    return lp->name;
1407    return NULL;
1408}
1409
1410/*
1411 * get_input - called when incoming data is available.
1412 */
1413static void
1414get_input()
1415{
1416    int len, i;
1417    u_char *p;
1418    u_short protocol;
1419    struct protent *protp;
1420
1421    p = inpacket_buf;	/* point to beginning of packet buffer */
1422
1423    len = read_packet(inpacket_buf);
1424    if (len < 0)
1425	return;
1426
1427    if (len == 0) {
1428	notice("Modem hangup");
1429	hungup = 1;
1430#ifdef __APPLE__
1431        if (status != EXIT_USER_REQUEST)
1432#endif
1433	status = EXIT_HANGUP;
1434	lcp_lowerdown(0);	/* serial link is no longer available */
1435	link_terminated(0);
1436	return;
1437    }
1438
1439    if (len < PPP_HDRLEN) {
1440#ifdef __APPLE__
1441	if (debug > 1)
1442#endif
1443	dbglog("received short packet:%.*B", len, p);
1444	return;
1445    }
1446
1447    dump_packet("rcvd", p, len);
1448    if (snoop_recv_hook) snoop_recv_hook(p, len);
1449
1450    p += 2;				/* Skip address and control */
1451    GETSHORT(protocol, p);
1452    len -= PPP_HDRLEN;
1453
1454    /*
1455     * Toss all non-LCP packets unless LCP is OPEN.
1456     */
1457    if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
1458#ifdef __APPLE__
1459	if (debug > 1)
1460#endif
1461	dbglog("Discarded non-LCP packet when LCP not open");
1462	return;
1463    }
1464
1465    /*
1466     * Until we get past the authentication phase, toss all packets
1467     * except LCP, LQR and authentication packets.
1468     */
1469    if (phase <= PHASE_AUTHENTICATE
1470	&& !(protocol == PPP_LCP || protocol == PPP_LQR
1471	     || protocol == PPP_PAP || protocol == PPP_CHAP ||
1472		protocol == PPP_EAP)) {
1473#ifdef __APPLE__
1474		if (unexpected_network_packet(0, protocol)) {
1475#endif
1476
1477#ifdef __APPLE__
1478	if (debug > 1)
1479#endif
1480	dbglog("discarding proto 0x%x in phase %d",
1481		   protocol, phase);
1482	return;
1483#ifdef __APPLE__
1484		}
1485#endif
1486    }
1487
1488    /*
1489     * Upcall the proper protocol input routine.
1490     */
1491    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
1492	if (protp->protocol == protocol && protp->enabled_flag) {
1493	    (*protp->input)(0, p, len);
1494	    return;
1495	}
1496#ifdef __APPLE__
1497		if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag) {
1498			if (protp->datainput != NULL) {
1499				(*protp->datainput)(0, p, len);
1500				return;
1501			}
1502			if (protp->state != NULL && (protp->state(0) == OPENED)) {
1503				// pppd receives data for a protocol in opened state.
1504				// this can happen if the peer sends packets too fast after its control protocol
1505				// reaches the opened state, pppd hasn't had time yet to process the control protocol
1506				// packet, and the kernel is still configured to reject the data packet.
1507				// in this case, just ignore the packet.
1508				// if this happens for an other reason, then there is probably a bug somewhere
1509				MAINDEBUG(("Data packet of protocol 0x%x received, with control prococol in opened state", protocol));
1510				return;
1511			}
1512		}
1513#else
1514        if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
1515	    && protp->datainput != NULL) {
1516	    (*protp->datainput)(0, p, len);
1517	    return;
1518	}
1519#endif
1520    }
1521
1522    if (debug) {
1523	const char *pname = protocol_name(protocol);
1524	if (pname != NULL)
1525	    warning("Unsupported protocol '%s' (0x%x) received", pname, protocol);
1526	else
1527	    warning("Unsupported protocol 0x%x received", protocol);
1528    }
1529    lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
1530}
1531
1532/*
1533 * ppp_send_config - configure the transmit-side characteristics of
1534 * the ppp interface.  Returns -1, indicating an error, if the channel
1535 * send_config procedure called error() (or incremented error_count
1536 * itself), otherwise 0.
1537 */
1538int
1539ppp_send_config(unit, mtu, accm, pcomp, accomp)
1540    int unit, mtu;
1541    u_int32_t accm;
1542    int pcomp, accomp;
1543{
1544	int errs;
1545
1546	if (the_channel->send_config == NULL)
1547		return 0;
1548	errs = error_count;
1549	(*the_channel->send_config)(mtu, accm, pcomp, accomp);
1550	return (error_count != errs)? -1: 0;
1551}
1552
1553/*
1554 * ppp_recv_config - configure the receive-side characteristics of
1555 * the ppp interface.  Returns -1, indicating an error, if the channel
1556 * recv_config procedure called error() (or incremented error_count
1557 * itself), otherwise 0.
1558 */
1559int
1560ppp_recv_config(unit, mru, accm, pcomp, accomp)
1561    int unit, mru;
1562    u_int32_t accm;
1563    int pcomp, accomp;
1564{
1565	int errs;
1566
1567	if (the_channel->recv_config == NULL)
1568		return 0;
1569	errs = error_count;
1570	(*the_channel->recv_config)(mru, accm, pcomp, accomp);
1571	return (error_count != errs)? -1: 0;
1572}
1573
1574/*
1575 * new_phase - signal the start of a new phase of pppd's operation.
1576 */
1577void
1578new_phase(p)
1579    int p;
1580{
1581    phase = p;
1582    if (new_phase_hook)
1583	(*new_phase_hook)(p);
1584    notify(phasechange, p);
1585}
1586
1587/*
1588 * die - clean up state and exit with the specified status.
1589 */
1590void
1591die(status)
1592    int status;
1593{
1594#ifndef __APPLE__
1595	print_link_stats();
1596#endif
1597    cleanup();
1598    notify(exitnotify, status);
1599    syslog(LOG_INFO, "Exit.");
1600    exit(status);
1601}
1602
1603/*
1604 * cleanup - restore anything which needs to be restored before we exit
1605 */
1606/* ARGSUSED */
1607static void
1608cleanup()
1609{
1610    sys_cleanup();
1611
1612    if (fd_ppp >= 0)
1613	the_channel->disestablish_ppp(devfd);
1614    if (the_channel->cleanup)
1615	(*the_channel->cleanup)();
1616
1617    if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
1618	warning("unable to delete pid file %s: %m", pidfilename);
1619    pidfilename[0] = 0;
1620    if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT)
1621	warning("unable to delete pid file %s: %m", linkpidfile);
1622    linkpidfile[0] = 0;
1623
1624#ifdef USE_TDB
1625    if (pppdb != NULL)
1626	cleanup_db();
1627#endif
1628
1629}
1630
1631void
1632print_link_stats()
1633{
1634    /*
1635     * Print connect time and statistics.
1636     */
1637    if (link_stats_valid) {
1638       int t = (link_connect_time + 5) / 6;    /* 1/10ths of minutes */
1639       info("Connect time %d.%d minutes.", t/10, t%10);
1640       info("Sent %u bytes, received %u bytes.",
1641	    link_stats.bytes_out, link_stats.bytes_in);
1642    }
1643}
1644
1645/*
1646 * update_link_stats - get stats at link termination.
1647 */
1648void
1649update_link_stats(u)
1650    int u;
1651{
1652    struct timeval now;
1653    char numbuf[32];
1654
1655    if (!get_ppp_stats(u, &link_stats)
1656	|| gettimeofday(&now, NULL) < 0)
1657	return;
1658    link_connect_time = now.tv_sec - start_time.tv_sec;
1659    link_stats_valid = 1;
1660
1661    slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time);
1662    script_setenv("CONNECT_TIME", numbuf, 0);
1663    slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out);
1664    script_setenv("BYTES_SENT", numbuf, 0);
1665    slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_in);
1666    script_setenv("BYTES_RCVD", numbuf, 0);
1667}
1668
1669
1670struct	callout {
1671    struct timeval	c_time;		/* time at which to call routine */
1672    void		*c_arg;		/* argument to routine */
1673    void		(*c_func) __P((void *)); /* routine */
1674    struct		callout *c_next;
1675};
1676
1677static struct callout *callout = NULL;	/* Callout list */
1678static struct timeval timenow;		/* Current time */
1679
1680/*
1681 * timeout - Schedule a timeout.
1682 */
1683void
1684timeout(func, arg, secs, usecs)
1685    void (*func) __P((void *));
1686    void *arg;
1687    int secs, usecs;
1688{
1689    struct callout *newp, *p, **pp;
1690
1691    MAINDEBUG(("Timeout %p:%p in %d.%03d seconds.", func, arg,
1692	       secs, usecs/1000));
1693
1694    /*
1695     * Allocate timeout.
1696     */
1697    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
1698	fatal("Out of memory in timeout()!");
1699    newp->c_arg = arg;
1700    newp->c_func = func;
1701#ifdef __APPLE__
1702    // timeout get screwed up if you change the current time of the machine...
1703    // use absolute time instead, as we are just interested in deltas, not actual time.
1704    getabsolutetime(&timenow);
1705#else
1706    gettimeofday(&timenow, NULL);
1707#endif
1708    newp->c_time.tv_sec = timenow.tv_sec + secs;
1709    newp->c_time.tv_usec = timenow.tv_usec + usecs;
1710    if (newp->c_time.tv_usec >= 1000000) {
1711	newp->c_time.tv_sec += newp->c_time.tv_usec / 1000000;
1712	newp->c_time.tv_usec %= 1000000;
1713    }
1714
1715    /*
1716     * Find correct place and link it in.
1717     */
1718    for (pp = &callout; (p = *pp); pp = &p->c_next)
1719	if (newp->c_time.tv_sec < p->c_time.tv_sec
1720	    || (newp->c_time.tv_sec == p->c_time.tv_sec
1721		&& newp->c_time.tv_usec < p->c_time.tv_usec))
1722	    break;
1723    newp->c_next = p;
1724    *pp = newp;
1725}
1726
1727
1728/*
1729 * untimeout - Unschedule a timeout.
1730 */
1731void
1732untimeout(func, arg)
1733    void (*func) __P((void *));
1734    void *arg;
1735{
1736    struct callout **copp, *freep;
1737
1738    MAINDEBUG(("Untimeout %p:%p.", func, arg));
1739
1740    /*
1741     * Find first matching timeout and remove it from the list.
1742     */
1743    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
1744	if (freep->c_func == func && freep->c_arg == arg) {
1745	    *copp = freep->c_next;
1746	    free((char *) freep);
1747	    break;
1748	}
1749}
1750
1751
1752/*
1753 * calltimeout - Call any timeout routines which are now due.
1754 */
1755static void
1756calltimeout()
1757{
1758    struct callout *p;
1759
1760    while (callout != NULL) {
1761	p = callout;
1762
1763#ifdef __APPLE__
1764        if (getabsolutetime(&timenow) < 0)
1765#else
1766	if (gettimeofday(&timenow, NULL) < 0)
1767#endif
1768	    fatal("Failed to get time of day: %m");
1769	if (!(p->c_time.tv_sec < timenow.tv_sec
1770	      || (p->c_time.tv_sec == timenow.tv_sec
1771		  && p->c_time.tv_usec <= timenow.tv_usec)))
1772	    break;		/* no, it's not time yet */
1773
1774	callout = p->c_next;
1775	(*p->c_func)(p->c_arg);
1776
1777	free((char *) p);
1778    }
1779}
1780
1781
1782/*
1783 * timeleft - return the length of time until the next timeout is due.
1784 */
1785static struct timeval *
1786timeleft(tvp)
1787    struct timeval *tvp;
1788{
1789    if (callout == NULL)
1790	return NULL;
1791
1792#ifdef __APPLE__
1793    getabsolutetime(&timenow);
1794#else
1795    gettimeofday(&timenow, NULL);
1796#endif
1797    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
1798    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
1799    if (tvp->tv_usec < 0) {
1800	tvp->tv_usec += 1000000;
1801	tvp->tv_sec -= 1;
1802    }
1803    if (tvp->tv_sec < 0)
1804	tvp->tv_sec = tvp->tv_usec = 0;
1805
1806    return tvp;
1807}
1808
1809
1810/*
1811 * kill_my_pg - send a signal to our process group, and ignore it ourselves.
1812 */
1813static void
1814kill_my_pg(sig)
1815    int sig;
1816{
1817    struct sigaction act, oldact;
1818
1819    act.sa_handler = SIG_IGN;
1820    act.sa_flags = 0;
1821    sigaction(sig, &act, &oldact);
1822    kill(0, sig);
1823    sigaction(sig, &oldact, NULL);
1824}
1825
1826
1827/*
1828 * hup - Catch SIGHUP signal.
1829 *
1830 * Indicates that the physical layer has been disconnected.
1831 * We don't rely on this indication; if the user has sent this
1832 * signal, we just take the link down.
1833 */
1834static void
1835hup(sig)
1836    int sig;
1837{
1838#ifdef __APPLE__
1839    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1840        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1841        /* <rdar://10258474> */
1842        return;
1843    }
1844#endif
1845    got_sighup = sig;
1846
1847#ifdef __APPLE__
1848    // connectors test that flag
1849    // handle event is not called when we are in the connect stage
1850    kill_link = 1;
1851#endif
1852
1853    if (conn_running)
1854	/* Send the signal to the [dis]connector process(es) also */
1855	kill_my_pg(sig);
1856    notify(sigreceived, sig);
1857#ifdef __APPLE__
1858    if (!hungup)
1859	status = EXIT_USER_REQUEST;
1860#endif
1861    if (waiting)
1862	siglongjmp(sigjmp, 1);
1863}
1864
1865
1866/*
1867 * term - Catch SIGTERM signal and SIGINT signal (^C/del).
1868 *
1869 * Indicates that we should initiate a graceful disconnect and exit.
1870 */
1871/*ARGSUSED*/
1872static void
1873term(sig)
1874    int sig;
1875{
1876#ifdef __APPLE__
1877    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1878        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1879        /* <rdar://10258474> */
1880        return;
1881    }
1882#endif
1883    got_sigterm = sig;
1884
1885#ifdef __APPLE__
1886    // connectors test that flag
1887    // handle event is not called when we are in the connect stage
1888    kill_link = 1;
1889    persist = 0;
1890    status = EXIT_USER_REQUEST;
1891#endif
1892
1893    if (conn_running)
1894	/* Send the signal to the [dis]connector process(es) also */
1895	kill_my_pg(sig);
1896    notify(sigreceived, sig);
1897    if (waiting)
1898	siglongjmp(sigjmp, 1);
1899}
1900
1901
1902/*
1903 * chld - Catch SIGCHLD signal.
1904 * Sets a flag so we will call reap_kids in the mainline.
1905 */
1906static void
1907chld(sig)
1908    int sig;
1909{
1910#ifdef __APPLE__
1911    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1912        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1913        /* <rdar://10258474> */
1914        return;
1915    }
1916#endif
1917    got_sigchld = 1;
1918    if (waiting)
1919	siglongjmp(sigjmp, 1);
1920}
1921
1922/*
1923 * stop - Catch SIGTSTP signal.
1924 *
1925 * Indicates that the physical is gone "on hold".
1926 * Stop all activity until we get the SIGCONT signal
1927 * or until we take the line down.
1928 */
1929static void
1930stop(sig)
1931    int sig;
1932{
1933
1934#ifdef __APPLE__
1935    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1936        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1937        /* <rdar://10258474> */
1938        return;
1939    }
1940#endif
1941    got_sigtstp = sig;
1942    switch (phase) {
1943        case PHASE_ONHOLD:	// already on hold
1944            break;
1945        case PHASE_RUNNING:	// needs to stop connection
1946            break;
1947        default:		// other states, simulate a sighup
1948            got_sighup = 1;
1949            if (conn_running)
1950                /* Send the signal to the [dis]connector process(es) also */
1951                kill_my_pg(sig);
1952    }
1953    notify(sigreceived, sig);
1954    if (waiting)
1955	siglongjmp(sigjmp, 1);
1956}
1957
1958/*
1959 * cont - Catch SIGCONT signal.
1960 *
1961 * resume all previously stopped activities.
1962 *
1963 */
1964static void
1965cont(sig)
1966    int sig;
1967{
1968#ifdef __APPLE__
1969    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1970        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1971        /* <rdar://10258474> */
1972        return;
1973    }
1974#endif
1975    got_sigcont = sig;
1976    notify(sigreceived, sig);
1977    if (waiting)
1978	siglongjmp(sigjmp, 1);
1979}
1980
1981/*
1982 * toggle_debug - Catch SIGUSR1 signal.
1983 *
1984 * Toggle debug flag.
1985 */
1986/*ARGSUSED*/
1987static void
1988toggle_debug(sig)
1989    int sig;
1990{
1991#ifdef __APPLE__
1992    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
1993        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
1994        /* <rdar://10258474> */
1995        return;
1996    }
1997#endif
1998    debug = !debug;
1999    if (debug) {
2000	setlogmask(LOG_UPTO(LOG_DEBUG));
2001    } else {
2002	setlogmask(LOG_UPTO(LOG_WARNING));
2003    }
2004}
2005
2006
2007/*
2008 * open_ccp - Catch SIGUSR2 signal.
2009 *
2010 * Try to (re)negotiate compression.
2011 */
2012/*ARGSUSED*/
2013static void
2014open_ccp(sig)
2015    int sig;
2016{
2017#ifdef __APPLE__
2018    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
2019        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
2020        /* <rdar://10258474> */
2021        return;
2022    }
2023#endif
2024    got_sigusr2 = 1;
2025    if (waiting)
2026	siglongjmp(sigjmp, 1);
2027}
2028
2029
2030/*
2031 * bad_signal - We've caught a fatal signal.  Clean up state and exit.
2032 */
2033static void
2034bad_signal(sig)
2035    int sig;
2036{
2037    static int crashed = 0;
2038
2039#ifdef __APPLE__
2040    if (mainthread_id && !(pthread_equal(mainthread_id, pthread_self()))){
2041        /* ignore signals if it's not the main thread, we will be dropping sigals but that's insignificant */
2042        /* <rdar://10258474> */
2043        return;
2044    }
2045#endif
2046    if (crashed)
2047	_exit(127);
2048    crashed = 1;
2049    error("Fatal signal %d", sig);
2050    if (conn_running)
2051	kill_my_pg(SIGTERM);
2052    notify(sigreceived, sig);
2053    die(127);
2054}
2055
2056/*
2057 * safe_fork - Create a child process.  The child closes all the
2058 * file descriptors that we don't want to leak to a script.
2059 * The parent waits for the child to do this before returning.
2060 */
2061pid_t
2062safe_fork()
2063{
2064	pid_t pid;
2065	int pipefd[2];
2066	char buf[1];
2067
2068	if (pipe(pipefd) == -1)
2069		pipefd[0] = pipefd[1] = -1;
2070	pid = fork();
2071	if (pid < 0)
2072		return -1;
2073	if (pid > 0) {
2074		close(pipefd[1]);
2075		/* this read() blocks until the close(pipefd[1]) below */
2076		complete_read(pipefd[0], buf, 1);
2077		close(pipefd[0]);
2078		return pid;
2079	}
2080	sys_close();
2081#ifdef __APPLE__
2082	options_close();
2083#endif
2084#ifdef USE_TDB
2085	tdb_close(pppdb);
2086#endif
2087	notify(fork_notifier, 0);
2088	close(pipefd[0]);
2089	/* this close unblocks the read() call above in the parent */
2090	close(pipefd[1]);
2091	return 0;
2092}
2093
2094/*
2095 * device_script - run a program to talk to the specified fds
2096 * (e.g. to run the connector or disconnector script).
2097 * stderr gets connected to the log fd or to the _PATH_CONNERRS file.
2098 */
2099#ifdef __APPLE__
2100#define PPP_ARG_FD 3
2101int
2102device_script(program, in, out, dont_wait, program_uid, pipe_args, pipe_args_len)
2103    char *program;
2104    int in, out;
2105    int dont_wait;
2106	uid_t program_uid;
2107	char *pipe_args;
2108	int pipe_args_len;
2109#else
2110int
2111device_script(program, in, out, dont_wait)
2112    char *program;
2113    int in, out;
2114    int dont_wait;
2115#endif
2116{
2117    int pid;
2118    int status = -1;
2119    int errfd;
2120    int fd;
2121	int fdp[2];
2122
2123//error("device script '%s'\n", program);
2124
2125	fdp[0] = fdp[1] = -1;
2126    if (pipe_args) {
2127		if (pipe(fdp) == -1) {
2128			error("Failed to setup pipe with device script: %m");
2129			return -1;
2130		}
2131	}
2132
2133    ++conn_running;
2134    pid = safe_fork();
2135
2136    if (pid < 0) {
2137		--conn_running;
2138		error("Failed to create child process: %m");
2139		return -1;
2140    }
2141
2142	if (pid > 0) {
2143		// running in parent
2144		// close read end of the pipe
2145			if (fdp[0] != -1) {
2146			close(fdp[0]);
2147			fdp[0] = -1;
2148		}
2149		// write args on the write end of the pipe, and close it
2150			if (fdp[1] != -1) {
2151			write(fdp[1], pipe_args, pipe_args_len);
2152			close(fdp[1]);
2153			fdp[1] = -1;
2154		}
2155		if (dont_wait) {
2156			record_child(pid, program, NULL, NULL);
2157			status = 0;
2158		} else {
2159			while (waitpid(pid, &status, 0) < 0) {
2160				if (errno == EINTR)
2161					continue;
2162				fatal("error waiting for (dis)connection process: %m");
2163			}
2164			--conn_running;
2165		}
2166#ifdef __APPLE__
2167	// return real status code
2168	// Fix me :	return only the lowest 8 bits
2169			return WEXITSTATUS(status);
2170#else
2171		return (status == 0 ? 0 : -1);
2172#endif
2173	}
2174
2175	/* here we are executing in the child */
2176
2177	/* make sure fds 0, 1, 2 are occupied */
2178	while ((fd = dup(in)) >= 0) {
2179		if (fd > 2) {
2180			close(fd);
2181			break;
2182		}
2183	}
2184
2185    /* dup in and out to fds > 2 */
2186    {
2187	int fd1 = in, fd2 = out, fd3 = log_to_fd;
2188
2189	in = dup(in);
2190	out = dup(out);
2191	if (log_to_fd >= 0) {
2192	    errfd = dup(log_to_fd);
2193	} else {
2194	    errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
2195	}
2196	close(fd1);
2197	close(fd2);
2198	close(fd3);
2199    }
2200
2201    /* close fds 0 - 2 and any others we can think of */
2202    close(0);
2203    close(1);
2204    close(2);
2205    if (the_channel->close)
2206	(*the_channel->close)();
2207    closelog();
2208    close(fd_devnull);
2209	if (fdp[1] != -1) {
2210		close(fdp[1]);
2211		fdp[1] = -1;
2212	}
2213
2214    /* dup the in, out, err fds to 0, 1, 2 */
2215    dup2(in, 0);
2216    close(in);
2217    dup2(out, 1);
2218    close(out);
2219    if (errfd >= 0) {
2220	dup2(errfd, 2);
2221	close(errfd);
2222    }
2223
2224#ifdef __APPLE__
2225    if (fdp[0] != -1) {
2226        dup2(fdp[0], PPP_ARG_FD);
2227        close(fdp[0]);
2228        fdp[0] = PPP_ARG_FD;
2229        closeallfrom(PPP_ARG_FD + 1);
2230    } else {
2231        /* make sure all fds 3 and above get closed, in case a library leaked */
2232        closeallfrom(3);
2233    }
2234
2235    if (program_uid == -1)
2236        program_uid = uid;
2237    setuid(program_uid);
2238    if (getuid() != program_uid) {
2239	error("setuid failed");
2240	exit(1);
2241    }
2242    setgid(getgid());
2243#else
2244    setuid(uid);
2245    if (getuid() != uid) {
2246	error("setuid failed");
2247	exit(1);
2248    }
2249    setgid(getgid());
2250	}
2251#endif
2252    execle("/bin/sh", "sh", "-c", program, (char *)0, (char *)0);
2253    error("could not exec /bin/sh: %m");
2254    exit(99);
2255    /* NOTREACHED */
2256}
2257
2258
2259/*
2260 * run-program - execute a program with given arguments,
2261 * but don't wait for it.
2262 * If the program can't be executed, logs an error unless
2263 * must_exist is 0 and the program file doesn't exist.
2264 * Returns -1 if it couldn't fork, 0 if the file doesn't exist
2265 * or isn't an executable plain file, or the process ID of the child.
2266 * If done != NULL, (*done)(arg) will be called later (within
2267 * reap_kids) iff the return value is > 0.
2268 */
2269pid_t
2270run_program(prog, args, must_exist, done, arg)
2271    char *prog;
2272    char **args;
2273    int must_exist;
2274    void (*done) __P((void *));
2275    void *arg;
2276{
2277    int pid;
2278    struct stat sbuf;
2279
2280    /*
2281     * First check if the file exists and is executable.
2282     * We don't use access() because that would use the
2283     * real user-id, which might not be root, and the script
2284     * might be accessible only to root.
2285     */
2286    errno = EINVAL;
2287    if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)
2288	|| (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) {
2289	if (must_exist || errno != ENOENT)
2290	    warning("Can't execute %s: %m", prog);
2291
2292	return 0;
2293    }
2294
2295    pid = safe_fork();
2296    if (pid == -1) {
2297	error("Failed to create child process for %s: %m", prog);
2298	return -1;
2299    }
2300    if (pid != 0) {
2301	if (debug)
2302	    dbglog("Script %s started (pid %d)", prog, pid);
2303	record_child(pid, prog, done, arg);
2304	return pid;
2305    }
2306
2307    /* Leave the current location */
2308    (void) setsid();	/* No controlling tty. */
2309    (void) umask (S_IRWXG|S_IRWXO);
2310    (void) chdir ("/");	/* no current directory. */
2311    setuid(0);		/* set real UID = root */
2312    setgid(getegid());
2313
2314    /* Ensure that nothing of our device environment is inherited. */
2315    closelog();
2316    if (the_channel->close)
2317	(*the_channel->close)();
2318
2319    /* Don't pass handles to the PPP device, even by accident. */
2320    dup2(fd_devnull, 0);
2321    dup2(fd_devnull, 1);
2322    dup2(fd_devnull, 2);
2323    close(fd_devnull);
2324
2325
2326#ifdef __APPLE__
2327	/* make sure all fd 3 and above, in case a library leaked */
2328	closeallfrom(3);
2329#endif
2330
2331#ifdef BSD
2332    /* Force the priority back to zero if pppd is running higher. */
2333    if (setpriority (PRIO_PROCESS, 0, 0) < 0)
2334	warning("can't reset priority to 0: %m");
2335#endif
2336
2337    /* SysV recommends a second fork at this point. */
2338
2339    /* run the program */
2340    execve(prog, args, script_env);
2341    if (must_exist || errno != ENOENT) {
2342	/* have to reopen the log, there's nowhere else
2343	   for the message to go. */
2344	reopen_log();
2345	syslog(LOG_ERR, "Can't execute %s: %m", prog);
2346	closelog();
2347    }
2348    _exit(-1);
2349}
2350
2351
2352/*
2353 * record_child - add a child process to the list for reap_kids
2354 * to use.
2355 */
2356void
2357record_child(pid, prog, done, arg)
2358    int pid;
2359    char *prog;
2360    void (*done) __P((void *));
2361    void *arg;
2362{
2363    struct subprocess *chp;
2364
2365    ++n_children;
2366
2367    chp = (struct subprocess *) malloc(sizeof(struct subprocess));
2368    if (chp == NULL) {
2369	warning("losing track of %s process", prog);
2370    } else {
2371	chp->pid = pid;
2372	chp->prog = prog;
2373	chp->done = done;
2374	chp->arg = arg;
2375	chp->next = children;
2376	children = chp;
2377    }
2378}
2379
2380
2381/*
2382 * reap_kids - get status from any dead child processes,
2383 * and log a message for abnormal terminations.
2384 */
2385static int
2386reap_kids(waitfor)
2387    int waitfor;
2388{
2389    int pid, status;
2390    struct subprocess *chp, **prevp;
2391
2392    if (n_children == 0)
2393	return 0;
2394    while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1
2395	   && pid != 0) {
2396	for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) {
2397	    if (chp->pid == pid) {
2398		--n_children;
2399		*prevp = chp->next;
2400		break;
2401	    }
2402	}
2403	if (WIFSIGNALED(status)) {
2404	    warning("Child process %s (pid %d) terminated with signal %d",
2405		 (chp? chp->prog: "??"), pid, WTERMSIG(status));
2406	} else if (debug)
2407	    dbglog("Script %s finished (pid %d), status = 0x%x",
2408		   (chp? chp->prog: "??"), pid,
2409		   WIFEXITED(status) ? WEXITSTATUS(status) : status);
2410	if (chp && chp->done)
2411	    (*chp->done)(chp->arg);
2412	if (chp)
2413	    free(chp);
2414    }
2415    if (pid == -1) {
2416	if (errno == ECHILD)
2417	    return -1;
2418	if (errno != EINTR)
2419	    error("Error waiting for child process: %m");
2420    }
2421    return 0;
2422}
2423
2424/*
2425 * add_notifier - add a new function to be called when something happens.
2426 */
2427void
2428add_notifier(notif, func, arg)
2429    struct notifier **notif;
2430    notify_func func;
2431    void *arg;
2432{
2433    struct notifier *np;
2434
2435    np = malloc(sizeof(struct notifier));
2436    if (np == 0)
2437	novm("notifier struct");
2438    np->next = *notif;
2439    np->func = func;
2440    np->arg = arg;
2441    *notif = np;
2442}
2443
2444void
2445add_notifier_last(notif, func, arg)
2446    struct notifier **notif;
2447    notify_func func;
2448    void *arg;
2449{
2450    struct notifier *np;
2451
2452    np = malloc(sizeof(struct notifier));
2453    if (np == 0)
2454        novm("notifier struct");
2455
2456    np->next = NULL;
2457    np->func = func;
2458    np->arg = arg;
2459
2460    if (*notif == NULL)
2461        *notif = np;
2462    else {
2463        struct notifier *cur = *notif;
2464        while (cur->next != NULL)
2465            cur = cur->next;
2466        cur->next = np;
2467    }
2468}
2469
2470/*
2471 * remove_notifier - remove a function from the list of things to
2472 * be called when something happens.
2473 */
2474void
2475remove_notifier(notif, func, arg)
2476    struct notifier **notif;
2477    notify_func func;
2478    void *arg;
2479{
2480    struct notifier *np;
2481
2482    for (; (np = *notif) != 0; notif = &np->next) {
2483	if (np->func == func && np->arg == arg) {
2484	    *notif = np->next;
2485	    free(np);
2486	    break;
2487	}
2488    }
2489}
2490
2491/*
2492 * notify - call a set of functions registered with add_notifier.
2493 */
2494void
2495notify(notif, val)
2496    struct notifier *notif;
2497    int val;
2498{
2499    struct notifier *np;
2500
2501    while ((np = notif) != 0) {
2502	notif = np->next;
2503	(*np->func)(np->arg, val);
2504    }
2505}
2506
2507/*
2508 * notify - call a set of functions registered with add_notifier using a unsigned 64-bit val (e.g a pointer).
2509 */
2510void
2511notify_with_ptr(notif, val)
2512    struct notifier *notif;
2513    uintptr_t val;
2514{
2515    struct notifier *np;
2516
2517    while ((np = notif) != 0) {
2518	notif = np->next;
2519	(*np->func)(np->arg, val);
2520    }
2521}
2522
2523/*
2524 * novm - log an error message saying we ran out of memory, and die.
2525 */
2526void
2527novm(msg)
2528    char *msg;
2529{
2530    fatal("Virtual memory exhausted allocating %s\n", msg);
2531}
2532
2533/*
2534 * script_setenv - set an environment variable value to be used
2535 * for scripts that we run (e.g. ip-up, auth-up, etc.)
2536 */
2537void
2538script_setenv(var, value, iskey)
2539    char *var, *value;
2540    int iskey;
2541{
2542    size_t varl = strlen(var);
2543    size_t vl = varl + strlen(value) + 2;
2544    int i;
2545    char *p, *newstring;
2546
2547    newstring = (char *) malloc(vl+1);
2548    if (newstring == 0)
2549	return;
2550
2551#ifdef USE_TDB
2552	/*
2553		The byte before the string is used to store the "iskey" value.
2554		It will be used later to know if delete_db_key() needs to be called.
2555		By moving the pointer to the actual start of the string, the original
2556		pointer to the allocated memory is "lost", and the string will appear
2557		as leaked in the 'leaks' command.
2558		This could be done better. It is only necessary when TDB is used.
2559	*/
2560    *newstring++ = iskey;
2561#endif
2562
2563    slprintf(newstring, vl, "%s=%s", var, value);
2564
2565    /* check if this variable is already set */
2566    if (script_env != 0) {
2567	for (i = 0; (p = script_env[i]) != 0; ++i) {
2568	    if (strncmp(p, var, varl) == 0 && p[varl] == '=') {
2569#ifdef USE_TDB
2570		if (p[-1] && pppdb != NULL)
2571		    delete_db_key(p);
2572#endif
2573#ifdef USE_TDB
2574		/* see comment about how "iskey" is stored */
2575		free(p-1);
2576#else
2577		free(p);
2578#endif
2579		script_env[i] = newstring;
2580#ifdef USE_TDB
2581		if (iskey && pppdb != NULL)
2582		    add_db_key(newstring);
2583		update_db_entry();
2584#endif
2585		return;
2586	    }
2587	}
2588    } else {
2589	/* no space allocated for script env. ptrs. yet */
2590	i = 0;
2591	script_env = (char **) malloc(16 * sizeof(char *));
2592	if (script_env == 0)
2593	    return;
2594	s_env_nalloc = 16;
2595    }
2596
2597    /* reallocate script_env with more space if needed */
2598    if (i + 1 >= s_env_nalloc) {
2599	int new_n = i + 17;
2600	char **newenv = (char **) realloc((void *)script_env,
2601					  new_n * sizeof(char *));
2602	if (newenv == 0)
2603	    return;
2604	script_env = newenv;
2605	s_env_nalloc = new_n;
2606    }
2607
2608    script_env[i] = newstring;
2609    script_env[i+1] = 0;
2610
2611#ifdef USE_TDB
2612    if (pppdb != NULL) {
2613	if (iskey)
2614	    add_db_key(newstring);
2615	update_db_entry();
2616    }
2617#endif
2618}
2619
2620/*
2621 * script_unsetenv - remove a variable from the environment
2622 * for scripts.
2623 */
2624void
2625script_unsetenv(var)
2626    char *var;
2627{
2628    int vl = strlen(var);
2629    int i;
2630    char *p;
2631
2632    if (script_env == 0)
2633	return;
2634    for (i = 0; (p = script_env[i]) != 0; ++i) {
2635	if (strncmp(p, var, vl) == 0 && p[vl] == '=') {
2636#ifdef USE_TDB
2637	    if (p[-1] && pppdb != NULL)
2638		delete_db_key(p);
2639#endif
2640#ifdef USE_TDB
2641		/* see comment about how "iskey" is stored */
2642		free(p-1);
2643#else
2644		free(p);
2645#endif
2646	    while ((script_env[i] = script_env[i+1]) != 0)
2647		++i;
2648	    break;
2649	}
2650    }
2651#ifdef USE_TDB
2652    if (pppdb != NULL)
2653	update_db_entry();
2654#endif
2655}
2656
2657#ifdef USE_TDB
2658/*
2659 * update_db_entry - update our entry in the database.
2660 */
2661static void
2662update_db_entry()
2663{
2664    TDB_DATA key, dbuf;
2665    int vlen, i;
2666    char *p, *q, *vbuf;
2667
2668    if (script_env == NULL)
2669	return;
2670    vlen = 0;
2671    for (i = 0; (p = script_env[i]) != 0; ++i)
2672	vlen += strlen(p) + 1;
2673    vbuf = malloc(vlen);
2674    if (vbuf == 0)
2675	novm("database entry");
2676    q = vbuf;
2677    for (i = 0; (p = script_env[i]) != 0; ++i)
2678	q += slprintf(q, vbuf + vlen - q, "%s;", p);
2679
2680    key.dptr = db_key;
2681    key.dsize = strlen(db_key);
2682    dbuf.dptr = vbuf;
2683    dbuf.dsize = vlen;
2684    if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
2685	error("tdb_store failed: %s", tdb_error(pppdb));
2686
2687    if (vbuf)
2688        free(vbuf);
2689
2690}
2691
2692/*
2693 * add_db_key - add a key that we can use to look up our database entry.
2694 */
2695static void
2696add_db_key(str)
2697    const char *str;
2698{
2699    TDB_DATA key, dbuf;
2700
2701    key.dptr = (char *) str;
2702    key.dsize = strlen(str);
2703    dbuf.dptr = db_key;
2704    dbuf.dsize = strlen(db_key);
2705    if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
2706	error("tdb_store key failed: %s", tdb_error(pppdb));
2707}
2708
2709/*
2710 * delete_db_key - delete a key for looking up our database entry.
2711 */
2712static void
2713delete_db_key(str)
2714    const char *str;
2715{
2716    TDB_DATA key;
2717
2718    key.dptr = (char *) str;
2719    key.dsize = strlen(str);
2720    tdb_delete(pppdb, key);
2721}
2722
2723/*
2724 * cleanup_db - delete all the entries we put in the database.
2725 */
2726static void
2727cleanup_db()
2728{
2729    TDB_DATA key;
2730    int i;
2731    char *p;
2732
2733    key.dptr = db_key;
2734    key.dsize = strlen(db_key);
2735    tdb_delete(pppdb, key);
2736    for (i = 0; (p = script_env[i]) != 0; ++i)
2737	if (p[-1])
2738	    delete_db_key(p);
2739}
2740#endif /* USE_TDB */
2741