main.c revision 1.51
1/*	$OpenBSD: main.c,v 1.51 2015/01/16 06:40:19 deraadt Exp $	*/
2
3/*
4 * main.c - Point-to-Point Protocol main module
5 *
6 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. The name "Carnegie Mellon University" must not be used to
21 *    endorse or promote products derived from this software without
22 *    prior written permission. For permission or any legal
23 *    details, please contact
24 *      Office of Technology Transfer
25 *      Carnegie Mellon University
26 *      5000 Forbes Avenue
27 *      Pittsburgh, PA  15213-3890
28 *      (412) 268-4387, fax: (412) 268-7395
29 *      tech-transfer@andrew.cmu.edu
30 *
31 * 4. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by Computing Services
34 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 *
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 */
44
45#include <sys/types.h>
46#include <sys/wait.h>
47#include <sys/time.h>
48#include <sys/resource.h>
49#include <sys/stat.h>
50#include <sys/socket.h>
51#include <net/if.h>
52#include <stdio.h>
53#include <ctype.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57#include <limits.h>
58#include <signal.h>
59#include <errno.h>
60#include <fcntl.h>
61#include <syslog.h>
62#include <netdb.h>
63#include <utmp.h>
64#include <pwd.h>
65
66#include "pppd.h"
67#include "magic.h"
68#include "fsm.h"
69#include "lcp.h"
70#include "ipcp.h"
71#include "upap.h"
72#include "chap.h"
73#include "ccp.h"
74#include "pathnames.h"
75#include "patchlevel.h"
76
77#ifdef CBCP_SUPPORT
78#include "cbcp.h"
79#endif
80
81#if defined(SUNOS4)
82extern char *strerror();
83#endif
84
85#ifdef AT_CHANGE
86#include "atcp.h"
87#endif
88
89/* interface vars */
90char ifname[IFNAMSIZ];		/* Interface name */
91int ifunit;			/* Interface unit number */
92
93char *progname;			/* Name of this program */
94char hostname[HOST_NAME_MAX+1];	/* Our hostname */
95static char pidfilename[PATH_MAX];	/* name of pid file */
96static char default_devnam[PATH_MAX];	/* name of default device */
97static pid_t pid;		/* Our pid */
98static uid_t uid;		/* Our real user-id */
99static int conn_running;	/* we have a [dis]connector running */
100static int crashed = 0;
101
102int ttyfd = -1;			/* Serial port file descriptor */
103mode_t tty_mode = -1;		/* Original access permissions to tty */
104int baud_rate;			/* Actual bits/second for serial device */
105int hungup;			/* terminal has been hung up */
106int privileged;			/* we're running as real uid root */
107int need_holdoff;		/* need holdoff period before restarting */
108int detached;			/* have detached from terminal */
109
110int phase;			/* where the link is at */
111int kill_link;
112int open_ccp_flag;
113
114char **script_env;		/* Env. variable values for scripts */
115int s_env_nalloc;		/* # words avail at script_env */
116
117u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
118u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
119
120static int n_children;		/* # child processes still running */
121
122static int locked;		/* lock() has succeeded */
123
124char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
125
126/* Prototypes for procedures local to this file. */
127
128static void create_pidfile(void);
129static void cleanup(void);
130static void close_tty(void);
131static void get_input(void);
132static void calltimeout(void);
133static struct timeval *timeleft(struct timeval *);
134static void kill_my_pg(int);
135static void hup(int);
136static void term(int);
137static void chld(int);
138static void toggle_debug(int);
139static void open_ccp(int);
140static void bad_signal(int);
141static void holdoff_end(void *);
142static int device_script(char *, int, int);
143static void reap_kids(void);
144static void pr_log(void *, char *, ...);
145
146extern	char	*ttyname(int);
147extern	char	*getlogin(void);
148int main(int, char *[]);
149
150#ifdef ultrix
151#undef	O_NONBLOCK
152#define	O_NONBLOCK	O_NDELAY
153#endif
154
155#ifdef ULTRIX
156#define setlogmask(x)
157#endif
158
159/*
160 * PPP Data Link Layer "protocol" table.
161 * One entry per supported protocol.
162 * The last entry must be NULL.
163 */
164struct protent *protocols[] = {
165    &lcp_protent,
166    &pap_protent,
167    &chap_protent,
168#ifdef CBCP_SUPPORT
169    &cbcp_protent,
170#endif
171    &ipcp_protent,
172    &ccp_protent,
173#ifdef AT_CHANGE
174    &atcp_protent,
175#endif
176    NULL
177};
178
179int
180main(argc, argv)
181    int argc;
182    char *argv[];
183{
184    int i, fdflags;
185    struct sigaction sa;
186    char *p;
187    struct passwd *pw;
188    struct timeval timo;
189    sigset_t mask;
190    struct protent *protp;
191    struct stat statbuf;
192    char numbuf[16];
193
194    phase = PHASE_INITIALIZE;
195    p = ttyname(0);
196    if (p)
197	strlcpy(devnam, p, PATH_MAX);
198    strlcpy(default_devnam, devnam, sizeof default_devnam);
199
200    script_env = NULL;
201
202    /* Initialize syslog facilities */
203#ifdef ULTRIX
204    openlog("pppd", LOG_PID);
205#else
206    openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
207    setlogmask(LOG_UPTO(LOG_INFO));
208#endif
209
210    if (gethostname(hostname, sizeof hostname) < 0 ) {
211	option_error("Couldn't get hostname: %m");
212	die(1);
213    }
214
215    uid = getuid();
216    privileged = uid == 0;
217    snprintf(numbuf, sizeof numbuf, "%u", uid);
218    script_setenv("UID", numbuf);
219
220    /*
221     * Initialize to the standard option set, then parse, in order,
222     * the system options file, the user's options file,
223     * the tty's options file, and the command line arguments.
224     */
225    for (i = 0; (protp = protocols[i]) != NULL; ++i)
226	(*protp->init)(0);
227
228    progname = *argv;
229
230    if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
231	|| !options_from_user())
232	exit(1);
233    scan_args(argc-1, argv+1);	/* look for tty name on command line */
234    if (!options_for_tty()
235	|| !parse_args(argc-1, argv+1))
236	exit(1);
237
238    /*
239     * Check that we are running as root.
240     */
241    if (geteuid() != 0) {
242	option_error("must be root to run %s, since it is not setuid-root",
243		     argv[0]);
244	die(1);
245    }
246
247    if (!ppp_available()) {
248	option_error(no_ppp_msg);
249	exit(1);
250    }
251
252    /*
253     * Check that the options given are valid and consistent.
254     */
255    sys_check_options();
256    auth_check_options();
257    for (i = 0; (protp = protocols[i]) != NULL; ++i)
258	if (protp->check_options != NULL)
259	    (*protp->check_options)();
260    if (demand && connector == 0) {
261	option_error("connect script required for demand-dialling\n");
262	exit(1);
263    }
264
265    script_setenv("DEVICE", devnam);
266    snprintf(numbuf, sizeof numbuf, "%d", baud_rate);
267    script_setenv("SPEED", numbuf);
268
269    /*
270     * If the user has specified the default device name explicitly,
271     * pretend they hadn't.
272     */
273    if (!default_device && strcmp(devnam, default_devnam) == 0)
274	default_device = 1;
275    if (default_device)
276	nodetach = 1;
277
278    /*
279     * Initialize system-dependent stuff and magic number package.
280     */
281    sys_init();
282    magic_init();
283    if (debug)
284	setlogmask(LOG_UPTO(LOG_DEBUG));
285
286    /*
287     * Detach ourselves from the terminal, if required,
288     * and identify who is running us.
289     */
290    if (nodetach == 0)
291	detach();
292    pid = getpid();
293    p = getlogin();
294    if (p == NULL) {
295	pw = getpwuid(uid);
296	if (pw != NULL && pw->pw_name != NULL)
297	    p = pw->pw_name;
298	else
299	    p = "(unknown)";
300    }
301    syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %u",
302	   VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid);
303
304    /*
305     * Compute mask of all interesting signals and install signal handlers
306     * for each.  Only one signal handler may be active at a time.  Therefore,
307     * all other signals should be masked when any handler is executing.
308     */
309    sigemptyset(&mask);
310    sigaddset(&mask, SIGHUP);
311    sigaddset(&mask, SIGINT);
312    sigaddset(&mask, SIGTERM);
313    sigaddset(&mask, SIGCHLD);
314
315#define SIGNAL(s, handler)	{ \
316	sa.sa_handler = handler; \
317	if (sigaction(s, &sa, NULL) < 0) { \
318	    syslog(LOG_ERR, "Couldn't establish signal handler (%d): %m", s); \
319	    die(1); \
320	} \
321    }
322
323    sa.sa_mask = mask;
324    sa.sa_flags = 0;
325    SIGNAL(SIGHUP, hup);		/* Hangup */
326    SIGNAL(SIGINT, term);		/* Interrupt */
327    SIGNAL(SIGTERM, term);		/* Terminate */
328    SIGNAL(SIGCHLD, chld);
329
330    SIGNAL(SIGUSR1, toggle_debug);	/* Toggle debug flag */
331    SIGNAL(SIGUSR2, open_ccp);		/* Reopen CCP */
332
333    /*
334     * Install a handler for other signals which would otherwise
335     * cause pppd to exit without cleaning up.
336     */
337    SIGNAL(SIGABRT, bad_signal);
338    SIGNAL(SIGALRM, bad_signal);
339    SIGNAL(SIGFPE, bad_signal);
340    SIGNAL(SIGILL, bad_signal);
341    SIGNAL(SIGPIPE, bad_signal);
342    SIGNAL(SIGQUIT, bad_signal);
343#if SIGSEGV_CHECK
344    SIGNAL(SIGSEGV, bad_signal);
345#endif
346#ifdef SIGBUS
347    SIGNAL(SIGBUS, bad_signal);
348#endif
349#ifdef SIGEMT
350    SIGNAL(SIGEMT, bad_signal);
351#endif
352#ifdef SIGPOLL
353    SIGNAL(SIGPOLL, bad_signal);
354#endif
355#ifdef SIGPROF
356    SIGNAL(SIGPROF, bad_signal);
357#endif
358#ifdef SIGSYS
359    SIGNAL(SIGSYS, bad_signal);
360#endif
361#ifdef SIGTRAP
362    SIGNAL(SIGTRAP, bad_signal);
363#endif
364#ifdef SIGVTALRM
365    SIGNAL(SIGVTALRM, bad_signal);
366#endif
367#ifdef SIGXCPU
368    SIGNAL(SIGXCPU, bad_signal);
369#endif
370#ifdef SIGXFSZ
371    SIGNAL(SIGXFSZ, bad_signal);
372#endif
373
374    /*
375     * Apparently we can get a SIGPIPE when we call syslog, if
376     * syslogd has died and been restarted.  Ignoring it seems
377     * be sufficient.
378     */
379    signal(SIGPIPE, SIG_IGN);
380
381    /*
382     * If we're doing dial-on-demand, set up the interface now.
383     */
384    if (demand) {
385	/*
386	 * Open the loopback channel and set it up to be the ppp interface.
387	 */
388	open_ppp_loopback();
389
390	syslog(LOG_INFO, "Using interface ppp%d", ifunit);
391	(void) snprintf(ifname, sizeof ifname, "ppp%d", ifunit);
392	script_setenv("IFNAME", ifname);
393
394	create_pidfile();	/* write pid to file */
395
396	/*
397	 * Configure the interface and mark it up, etc.
398	 */
399	demand_conf();
400    }
401
402    for (;;) {
403
404	need_holdoff = 1;
405
406	if (demand) {
407	    /*
408	     * Don't do anything until we see some activity.
409	     */
410	    phase = PHASE_DORMANT;
411	    kill_link = 0;
412	    demand_unblock();
413	    for (;;) {
414		wait_loop_output(timeleft(&timo));
415		calltimeout();
416		if (kill_link) {
417		    if (!persist)
418			die(0);
419		    kill_link = 0;
420		}
421		if (get_loop_output())
422		    break;
423		reap_kids();
424	    }
425
426	    /*
427	     * Now we want to bring up the link.
428	     */
429	    demand_drop();
430	    syslog(LOG_INFO, "Starting link");
431	}
432
433	/*
434	 * Lock the device if we've been asked to.
435	 */
436	if (lockflag && !default_device) {
437	    if (lock(devnam) < 0)
438		goto fail;
439	    locked = 1;
440	}
441
442	/*
443	 * Open the serial device and set it up to be the ppp interface.
444	 * First we open it in non-blocking mode so we can set the
445	 * various termios flags appropriately.  If we aren't dialling
446	 * out and we want to use the modem lines, we reopen it later
447	 * in order to wait for the carrier detect signal from the modem.
448	 */
449	while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) {
450	    if (errno != EINTR)
451		syslog(LOG_ERR, "Failed to open %s: %m", devnam);
452	    if (!persist || errno != EINTR)
453		goto fail;
454	}
455	if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
456	    || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
457	    syslog(LOG_WARNING,
458		   "Couldn't reset non-blocking mode on device: %m");
459
460	hungup = 0;
461	kill_link = 0;
462
463	/*
464	 * Do the equivalent of `mesg n' to stop broadcast messages.
465	 */
466	if (fstat(ttyfd, &statbuf) < 0
467	    || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
468	    syslog(LOG_WARNING,
469		   "Couldn't restrict write permissions to %s: %m", devnam);
470	} else
471	    tty_mode = statbuf.st_mode;
472
473	/* run connection script */
474	if (connector && connector[0]) {
475	    MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector));
476
477	    /*
478	     * Set line speed, flow control, etc.
479	     * On most systems we set CLOCAL for now so that we can talk
480	     * to the modem before carrier comes up.  But this has the
481	     * side effect that we might miss it if CD drops before we
482	     * get to clear CLOCAL below.  On systems where we can talk
483	     * successfully to the modem with CLOCAL clear and CD down,
484	     * we can clear CLOCAL at this point.
485	     */
486	    set_up_tty(ttyfd, (modem_chat == 0));
487
488	    /* drop dtr to hang up in case modem is off hook */
489	    if (!default_device && modem) {
490		setdtr(ttyfd, FALSE);
491		sleep(1);
492		setdtr(ttyfd, TRUE);
493	    }
494
495	    if (device_script(connector, ttyfd, ttyfd) < 0) {
496		syslog(LOG_ERR, "Connect script failed");
497		setdtr(ttyfd, FALSE);
498		goto fail;
499	    }
500
501	    syslog(LOG_INFO, "Serial connection established.");
502	    sleep(1);		/* give it time to set up its terminal */
503	}
504
505	set_up_tty(ttyfd, 0);
506
507	/* reopen tty if necessary to wait for carrier */
508	if (connector == NULL && modem) {
509	    while ((i = open(devnam, O_RDWR)) < 0) {
510		if (errno != EINTR)
511		    syslog(LOG_ERR, "Failed to reopen %s: %m", devnam);
512		if (!persist || errno != EINTR || hungup || kill_link)
513		    goto fail;
514	    }
515	    close(i);
516	}
517
518	/* run welcome script, if any */
519	if (welcomer && welcomer[0]) {
520	    if (device_script(welcomer, ttyfd, ttyfd) < 0)
521		syslog(LOG_WARNING, "Welcome script failed");
522	}
523
524	/* set up the serial device as a ppp interface */
525	establish_ppp(ttyfd);
526
527	if (!demand) {
528
529	    syslog(LOG_INFO, "Using interface ppp%d", ifunit);
530	    (void) snprintf(ifname, sizeof ifname, "ppp%d", ifunit);
531	    script_setenv("IFNAME", ifname);
532
533	    create_pidfile();	/* write pid to file */
534	}
535
536	/*
537	 * Start opening the connection and wait for
538	 * incoming events (reply, timeout, etc.).
539	 */
540	syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
541	lcp_lowerup(0);
542	lcp_open(0);		/* Start protocol */
543	for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) {
544	    wait_input(timeleft(&timo));
545	    calltimeout();
546	    get_input();
547	    if (kill_link) {
548		lcp_close(0, "User request");
549		kill_link = 0;
550	    }
551	    if (open_ccp_flag) {
552		if (phase == PHASE_NETWORK) {
553		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
554		    (*ccp_protent.open)(0);
555		}
556		open_ccp_flag = 0;
557	    }
558	    reap_kids();	/* Don't leave dead kids lying around */
559	}
560
561	/*
562	 * If we may want to bring the link up again, transfer
563	 * the ppp unit back to the loopback.  Set the
564	 * real serial device back to its normal mode of operation.
565	 */
566	clean_check();
567	if (demand)
568	    restore_loop();
569	disestablish_ppp(ttyfd);
570
571	/*
572	 * Run disconnector script, if requested.
573	 * XXX we may not be able to do this if the line has hung up!
574	 */
575	if (disconnector && !hungup) {
576	    set_up_tty(ttyfd, 1);
577	    if (device_script(disconnector, ttyfd, ttyfd) < 0) {
578		syslog(LOG_WARNING, "disconnect script failed");
579	    } else {
580		syslog(LOG_INFO, "Serial link disconnected.");
581	    }
582	}
583
584    fail:
585	if (ttyfd >= 0)
586	    close_tty();
587	if (locked) {
588	    unlock();
589	    locked = 0;
590	}
591
592	if (!demand) {
593	    if (pidfilename[0] != 0
594		&& unlink(pidfilename) < 0 && errno != ENOENT)
595		syslog(LOG_WARNING, "unable to delete pid file: %m");
596	    pidfilename[0] = 0;
597	}
598
599	if (!persist)
600	    die(1);
601
602	if (holdoff > 0 && need_holdoff) {
603	    phase = PHASE_HOLDOFF;
604	    TIMEOUT(holdoff_end, NULL, holdoff);
605	    do {
606		wait_time(timeleft(&timo));
607		calltimeout();
608		if (kill_link) {
609		    if (!persist)
610			die(0);
611		    kill_link = 0;
612		    phase = PHASE_DORMANT; /* allow signal to end holdoff */
613		}
614		reap_kids();
615	    } while (phase == PHASE_HOLDOFF);
616	}
617    }
618
619    die(0);
620    return 0;
621}
622
623/*
624 * detach - detach us from the controlling terminal.
625 */
626void
627detach()
628{
629    if (detached)
630	return;
631    if (daemon(0, 0) < 0) {
632	perror("Couldn't detach from controlling terminal");
633	die(1);
634    }
635    detached = 1;
636    pid = getpid();
637    /* update pid file if it has been written already */
638    if (pidfilename[0])
639	create_pidfile();
640}
641
642/*
643 * Create a file containing our process ID.
644 */
645static void
646create_pidfile()
647{
648    FILE *pidfile;
649
650    (void) snprintf(pidfilename, sizeof pidfilename,
651	"%s%s.pid", _PATH_VARRUN, ifname);
652    if ((pidfile = fopen(pidfilename, "w")) != NULL) {
653	fprintf(pidfile, "%ld\n", (long)pid);
654	(void) fclose(pidfile);
655    } else {
656	syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
657	pidfilename[0] = 0;
658    }
659}
660
661/*
662 * holdoff_end - called via a timeout when the holdoff period ends.
663 */
664static void
665holdoff_end(arg)
666    void *arg;
667{
668    phase = PHASE_DORMANT;
669}
670
671/*
672 * get_input - called when incoming data is available.
673 */
674static void
675get_input()
676{
677    int len, i;
678    u_char *p;
679    u_short protocol;
680    struct protent *protp;
681
682    p = inpacket_buf;	/* point to beginning of packet buffer */
683
684    len = read_packet(inpacket_buf);
685    if (len < 0)
686	return;
687
688    if (len == 0) {
689	syslog(LOG_NOTICE, "Modem hangup");
690	hungup = 1;
691	lcp_lowerdown(0);	/* serial link is no longer available */
692	link_terminated(0);
693	return;
694    }
695
696    if (debug /*&& (debugflags & DBG_INPACKET)*/)
697	log_packet(p, len, "rcvd ", LOG_DEBUG);
698
699    if (len < PPP_HDRLEN) {
700	MAINDEBUG((LOG_INFO, "io(): Received short packet."));
701	return;
702    }
703
704    p += 2;				/* Skip address and control */
705    GETSHORT(protocol, p);
706    len -= PPP_HDRLEN;
707
708    /*
709     * Toss all non-LCP packets unless LCP is OPEN.
710     */
711    if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
712	MAINDEBUG((LOG_INFO,
713		   "get_input: Received non-LCP packet when LCP not open."));
714	return;
715    }
716
717    /*
718     * Until we get past the authentication phase, toss all packets
719     * except LCP, LQR and authentication packets.
720     */
721    if (phase <= PHASE_AUTHENTICATE
722	&& !(protocol == PPP_LCP || protocol == PPP_LQR
723	|| protocol == PPP_PAP || protocol == PPP_CHAP)) {
724	MAINDEBUG((LOG_INFO, "get_input: discarding proto 0x%x in phase %d",
725		   protocol, phase));
726	return;
727    }
728
729    /*
730     * Upcall the proper protocol input routine.
731     */
732    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
733	if (protp->protocol == protocol && protp->enabled_flag) {
734	    (*protp->input)(0, p, len);
735	    return;
736	}
737	if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
738	    && protp->datainput != NULL) {
739	    (*protp->datainput)(0, p, len);
740	    return;
741	}
742    }
743
744    if (debug)
745    	syslog(LOG_WARNING, "Unsupported protocol (0x%x) received", protocol);
746    lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
747}
748
749
750/*
751 * quit - Clean up state and exit (with an error indication).
752 */
753void
754quit()
755{
756    die(1);
757}
758
759/*
760 * die - like quit, except we can specify an exit status.
761 */
762void
763die(status)
764    int status;
765{
766    struct syslog_data sdata = SYSLOG_DATA_INIT;
767
768    cleanup();
769    syslog_r(LOG_INFO, &sdata, "Exit.");
770    _exit(status);
771}
772
773/*
774 * cleanup - restore anything which needs to be restored before we exit
775 */
776/* ARGSUSED */
777static void
778cleanup()
779{
780    sys_cleanup();
781
782    if (ttyfd >= 0)
783	close_tty();
784
785    if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
786	syslog(LOG_WARNING, "unable to delete pid file: %m");
787    pidfilename[0] = 0;
788
789    if (locked)
790	unlock();
791}
792
793/*
794 * close_tty - restore the terminal device and close it.
795 */
796static void
797close_tty()
798{
799    disestablish_ppp(ttyfd);
800
801    /* drop dtr to hang up */
802    if (modem) {
803	setdtr(ttyfd, FALSE);
804	/*
805	 * This sleep is in case the serial port has CLOCAL set by default,
806	 * and consequently will reassert DTR when we close the device.
807	 */
808	sleep(1);
809    }
810
811    restore_tty(ttyfd);
812
813    if (tty_mode != (mode_t) -1)
814	fchmod(ttyfd, tty_mode);
815
816    close(ttyfd);
817    ttyfd = -1;
818}
819
820
821struct	callout {
822    struct timeval	c_time;		/* time at which to call routine */
823    void		*c_arg;		/* argument to routine */
824    void		(*c_func)(void *); /* routine */
825    struct		callout *c_next;
826};
827
828static struct callout *callout = NULL;	/* Callout list */
829static struct timeval timenow;		/* Current time */
830
831/*
832 * timeout - Schedule a timeout.
833 *
834 * Note that this timeout takes the number of seconds, NOT hz (as in
835 * the kernel).
836 */
837void
838timeout(func, arg, time)
839    void (*func)(void *);
840    void *arg;
841    int time;
842{
843    struct callout *newp, *p, **pp;
844
845    MAINDEBUG((LOG_DEBUG, "Timeout %lx:%lx in %d seconds.",
846	       (long) func, (long) arg, time));
847
848    /*
849     * Allocate timeout.
850     */
851    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
852	syslog(LOG_ERR, "Out of memory in timeout()!");
853	die(1);
854    }
855    newp->c_arg = arg;
856    newp->c_func = func;
857    gettimeofday(&timenow, NULL);
858    newp->c_time.tv_sec = timenow.tv_sec + time;
859    newp->c_time.tv_usec = timenow.tv_usec;
860
861    /*
862     * Find correct place and link it in.
863     */
864    for (pp = &callout; (p = *pp); pp = &p->c_next)
865	if (newp->c_time.tv_sec < p->c_time.tv_sec
866	    || (newp->c_time.tv_sec == p->c_time.tv_sec
867		&& newp->c_time.tv_usec < p->c_time.tv_sec))
868	    break;
869    newp->c_next = p;
870    *pp = newp;
871}
872
873
874/*
875 * untimeout - Unschedule a timeout.
876 */
877void
878untimeout(func, arg)
879    void (*func)(void *);
880    void *arg;
881{
882    struct callout **copp, *freep;
883
884    MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg));
885
886    /*
887     * Find first matching timeout and remove it from the list.
888     */
889    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
890	if (freep->c_func == func && freep->c_arg == arg) {
891	    *copp = freep->c_next;
892	    (void) free((char *) freep);
893	    break;
894	}
895}
896
897
898/*
899 * calltimeout - Call any timeout routines which are now due.
900 */
901static void
902calltimeout()
903{
904    struct callout *p;
905
906    while (callout != NULL) {
907	p = callout;
908
909	if (gettimeofday(&timenow, NULL) < 0) {
910	    syslog(LOG_ERR, "Failed to get time of day: %m");
911	    die(1);
912	}
913	if (!(p->c_time.tv_sec < timenow.tv_sec
914	      || (p->c_time.tv_sec == timenow.tv_sec
915		  && p->c_time.tv_usec <= timenow.tv_usec)))
916	    break;		/* no, it's not time yet */
917
918	callout = p->c_next;
919	(*p->c_func)(p->c_arg);
920
921	free((char *) p);
922    }
923}
924
925
926/*
927 * timeleft - return the length of time until the next timeout is due.
928 */
929static struct timeval *
930timeleft(tvp)
931    struct timeval *tvp;
932{
933    if (callout == NULL)
934	return NULL;
935
936    gettimeofday(&timenow, NULL);
937    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
938    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
939    if (tvp->tv_usec < 0) {
940	tvp->tv_usec += 1000000;
941	tvp->tv_sec -= 1;
942    }
943    if (tvp->tv_sec < 0)
944	tvp->tv_sec = tvp->tv_usec = 0;
945
946    return tvp;
947}
948
949
950/*
951 * kill_my_pg - send a signal to our process group, and ignore it ourselves.
952 */
953static void
954kill_my_pg(sig)
955    int sig;
956{
957    struct sigaction act, oldact;
958
959    act.sa_handler = SIG_IGN;
960    act.sa_flags = 0;
961    kill(0, sig);
962    sigaction(sig, &act, &oldact);
963    sigaction(sig, &oldact, NULL);
964}
965
966
967/*
968 * hup - Catch SIGHUP signal.
969 *
970 * Indicates that the physical layer has been disconnected.
971 * We don't rely on this indication; if the user has sent this
972 * signal, we just take the link down.
973 */
974static void
975hup(sig)
976    int sig;
977{
978    int save_errno = errno;
979    struct syslog_data sdata = SYSLOG_DATA_INIT;
980
981    if (crashed)
982	_exit(127);
983    syslog_r(LOG_INFO, &sdata, "Hangup (SIGHUP)");
984    kill_link = 1;
985    if (conn_running)
986	/* Send the signal to the [dis]connector process(es) also */
987	kill_my_pg(sig);
988    errno = save_errno;
989}
990
991
992/*
993 * term - Catch SIGTERM signal and SIGINT signal (^C/del).
994 *
995 * Indicates that we should initiate a graceful disconnect and exit.
996 */
997/*ARGSUSED*/
998static void
999term(sig)
1000    int sig;
1001{
1002    int save_errno = errno;
1003    struct syslog_data sdata = SYSLOG_DATA_INIT;
1004
1005    if (crashed)
1006	_exit(127);
1007    syslog_r(LOG_INFO, &sdata, "Terminating on signal %d.", sig);
1008    persist = 0;		/* don't try to restart */
1009    kill_link = 1;
1010    if (conn_running)
1011	/* Send the signal to the [dis]connector process(es) also */
1012	kill_my_pg(sig);
1013    errno = save_errno;
1014}
1015
1016
1017/*
1018 * chld - Catch SIGCHLD signal.
1019 * Calls reap_kids to get status for any dead kids.
1020 */
1021static void
1022chld(sig)
1023    int sig;
1024{
1025    int save_errno = errno;
1026
1027    reap_kids();		/* XXX somewhat unsafe */
1028    errno = save_errno;
1029}
1030
1031
1032/*
1033 * toggle_debug - Catch SIGUSR1 signal.
1034 *
1035 * Toggle debug flag.
1036 */
1037/*ARGSUSED*/
1038static void
1039toggle_debug(sig)
1040    int sig;
1041{
1042    debug = !debug;
1043    if (debug) {
1044	setlogmask(LOG_UPTO(LOG_DEBUG));	/* XXX safe, but wrong */
1045    } else {
1046	setlogmask(LOG_UPTO(LOG_WARNING));	/* XXX safe, but wrong */
1047    }
1048}
1049
1050
1051/*
1052 * open_ccp - Catch SIGUSR2 signal.
1053 *
1054 * Try to (re)negotiate compression.
1055 */
1056/*ARGSUSED*/
1057static void
1058open_ccp(sig)
1059    int sig;
1060{
1061    open_ccp_flag = 1;
1062}
1063
1064
1065/*
1066 * bad_signal - We've caught a fatal signal.  Clean up state and exit.
1067 */
1068static void
1069bad_signal(sig)
1070    int sig;
1071{
1072    struct syslog_data sdata = SYSLOG_DATA_INIT;
1073
1074    if (crashed)
1075	_exit(127);
1076    crashed = 1;
1077    syslog_r(LOG_ERR, &sdata, "Fatal signal %d", sig);
1078    if (conn_running)
1079	kill_my_pg(SIGTERM);
1080    die(1);					/* XXX unsafe! */
1081}
1082
1083
1084/*
1085 * device_script - run a program to connect or disconnect the
1086 * serial device.
1087 */
1088static int
1089device_script(program, in, out)
1090    char *program;
1091    int in, out;
1092{
1093    pid_t pid;
1094    int status;
1095    int errfd;
1096    gid_t gid;
1097    uid_t uid;
1098
1099    conn_running = 1;
1100    pid = fork();
1101
1102    if (pid < 0) {
1103	conn_running = 0;
1104	syslog(LOG_ERR, "Failed to create child process: %m");
1105	die(1);
1106    }
1107
1108    if (pid == 0) {
1109	sys_close();
1110	closelog();
1111	if (in == out) {
1112	    if (in != 0) {
1113		dup2(in, 0);
1114		close(in);
1115	    }
1116	    dup2(0, 1);
1117	} else {
1118	    if (out == 0)
1119		out = dup(out);
1120	    if (in != 0) {
1121		dup2(in, 0);
1122		close(in);
1123	    }
1124	    if (out != 1) {
1125		dup2(out, 1);
1126		close(out);
1127	    }
1128	}
1129	if (nodetach == 0) {
1130	    close(2);
1131	    errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
1132	    if (errfd >= 0 && errfd != 2) {
1133		dup2(errfd, 2);
1134		close(errfd);
1135	    }
1136	}
1137
1138	/* revoke privs */
1139	gid = getgid();
1140	uid = getuid();
1141	if (setresgid(gid, gid, gid) == -1 || setresuid(uid, uid, uid) == -1) {
1142		syslog(LOG_ERR, "revoke privileges: %s", strerror(errno));
1143		_exit(1);
1144	}
1145
1146	execl("/bin/sh", "sh", "-c", program, (char *)0);
1147	syslog(LOG_ERR, "could not exec /bin/sh: %m");
1148	_exit(99);
1149	/* NOTREACHED */
1150    }
1151
1152    while (waitpid(pid, &status, 0) < 0) {
1153	if (errno == EINTR)
1154	    continue;
1155	syslog(LOG_ERR, "error waiting for (dis)connection process: %m");
1156	die(1);
1157    }
1158    conn_running = 0;
1159
1160    return (status == 0 ? 0 : -1);
1161}
1162
1163
1164/*
1165 * run-program - execute a program with given arguments,
1166 * but don't wait for it.
1167 * If the program can't be executed, logs an error unless
1168 * must_exist is 0 and the program file doesn't exist.
1169 */
1170int
1171run_program(prog, args, must_exist)
1172    char *prog;
1173    char **args;
1174    int must_exist;
1175{
1176    pid_t pid;
1177    uid_t uid;
1178    gid_t gid;
1179
1180    pid = fork();
1181    if (pid == -1) {
1182	syslog(LOG_ERR, "Failed to create child process for %s: %m", prog);
1183	return -1;
1184    }
1185    if (pid == 0) {
1186	int new_fd;
1187
1188	/* Leave the current location */
1189	(void) setsid();    /* No controlling tty. */
1190	(void) umask (S_IRWXG|S_IRWXO);
1191	(void) chdir ("/"); /* no current directory. */
1192
1193	/* revoke privs */
1194	uid = getuid();
1195	gid = getgid();
1196	if (setresgid(gid, gid, gid) == -1 || setresuid(uid, uid, uid) == -1) {
1197		syslog(LOG_ERR, "revoke privileges: %s", strerror(errno));
1198		_exit(1);
1199	}
1200
1201	/* Ensure that nothing of our device environment is inherited. */
1202	sys_close();
1203	closelog();
1204	close (0);
1205	close (1);
1206	close (2);
1207	close (ttyfd);  /* tty interface to the ppp device */
1208
1209	/* Don't pass handles to the PPP device, even by accident. */
1210	new_fd = open (_PATH_DEVNULL, O_RDWR);
1211	if (new_fd >= 0) {
1212	    if (new_fd != 0) {
1213		dup2  (new_fd, 0); /* stdin <- /dev/null */
1214		close (new_fd);
1215	    }
1216	    dup2 (0, 1); /* stdout -> /dev/null */
1217	    dup2 (0, 2); /* stderr -> /dev/null */
1218	}
1219
1220	/* Force the priority back to zero if pppd is running higher. */
1221	if (setpriority (PRIO_PROCESS, 0, 0) < 0)
1222	    syslog (LOG_WARNING, "can't reset priority to 0: %m");
1223
1224	/* SysV recommends a second fork at this point. */
1225
1226	/* run the program; give it a null environment */
1227	execve(prog, args, script_env);
1228	if (must_exist || errno != ENOENT)
1229	    syslog(LOG_WARNING, "Can't execute %s: %m", prog);
1230	_exit(1);
1231    }
1232    MAINDEBUG((LOG_DEBUG, "Script %s started; pid = %ld", prog, (long)pid));
1233    ++n_children;
1234    return 0;
1235}
1236
1237
1238/*
1239 * reap_kids - get status from any dead child processes,
1240 * and log a message for abnormal terminations.
1241 */
1242static void
1243reap_kids()
1244{
1245    int status;
1246    pid_t pid;
1247
1248    if (n_children == 0)
1249	return;
1250    if ((pid = waitpid(-1, &status, WNOHANG)) == -1) {
1251	if (errno != ECHILD)
1252	    syslog(LOG_ERR, "Error waiting for child process: %m");
1253	return;
1254    }
1255    if (pid > 0) {
1256	--n_children;
1257	if (WIFSIGNALED(status)) {
1258	    syslog(LOG_WARNING, "Child process %ld terminated with signal %d",
1259		   (long)pid, WTERMSIG(status));
1260	}
1261    }
1262}
1263
1264
1265/*
1266 * log_packet - format a packet and log it.
1267 */
1268
1269char line[256];			/* line to be logged accumulated here */
1270char *linep;
1271
1272void
1273log_packet(p, len, prefix, level)
1274    u_char *p;
1275    int len;
1276    char *prefix;
1277    int level;
1278{
1279    strlcpy(line, prefix, sizeof line);
1280    linep = line + strlen(line);
1281    format_packet(p, len, pr_log, NULL);
1282    if (linep != line)
1283	syslog(level, "%s", line);
1284}
1285
1286/*
1287 * format_packet - make a readable representation of a packet,
1288 * calling `printer(arg, format, ...)' to output it.
1289 */
1290void
1291format_packet(p, len, printer, arg)
1292    u_char *p;
1293    int len;
1294    void (*printer)(void *, char *, ...);
1295    void *arg;
1296{
1297    int i, n;
1298    u_short proto;
1299    u_char x;
1300    struct protent *protp;
1301
1302    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
1303	p += 2;
1304	GETSHORT(proto, p);
1305	len -= PPP_HDRLEN;
1306	for (i = 0; (protp = protocols[i]) != NULL; ++i)
1307	    if (proto == protp->protocol)
1308		break;
1309	if (protp != NULL) {
1310	    printer(arg, "[%s", protp->name);
1311	    n = (*protp->printpkt)(p, len, printer, arg);
1312	    printer(arg, "]");
1313	    p += n;
1314	    len -= n;
1315	} else {
1316	    printer(arg, "[proto=0x%x]", proto);
1317	}
1318    }
1319
1320    for (; len > 0; --len) {
1321	GETCHAR(x, p);
1322	printer(arg, " %.2x", x);
1323    }
1324}
1325
1326static void
1327pr_log(void *arg, char *fmt, ...)
1328{
1329    int n;
1330    va_list pvar;
1331    char buf[256];
1332
1333    va_start(pvar, fmt);
1334
1335    n = vfmtmsg(buf, sizeof(buf), fmt, pvar);
1336    va_end(pvar);
1337
1338    if (linep + n + 1 > line + sizeof(line)) {
1339	syslog(LOG_DEBUG, "%s", line);
1340	linep = line;
1341    }
1342    strlcpy(linep, buf, line + sizeof line - linep);
1343    linep += n;
1344}
1345
1346/*
1347 * print_string - print a readable representation of a string using
1348 * printer.
1349 */
1350void
1351print_string(p, len, printer, arg)
1352    char *p;
1353    int len;
1354    void (*printer)(void *, char *, ...);
1355    void *arg;
1356{
1357    int c;
1358
1359    printer(arg, "\"");
1360    for (; len > 0; --len) {
1361	c = *p++;
1362	if (' ' <= c && c <= '~') {
1363	    if (c == '\\' || c == '"')
1364		printer(arg, "\\");
1365	    printer(arg, "%c", c);
1366	} else {
1367	    switch (c) {
1368	    case '\n':
1369		printer(arg, "\\n");
1370		break;
1371	    case '\r':
1372		printer(arg, "\\r");
1373		break;
1374	    case '\t':
1375		printer(arg, "\\t");
1376		break;
1377	    default:
1378		printer(arg, "\\%.3o", c);
1379	    }
1380	}
1381    }
1382    printer(arg, "\"");
1383}
1384
1385/*
1386 * novm - log an error message saying we ran out of memory, and die.
1387 */
1388void
1389novm(msg)
1390    char *msg;
1391{
1392    syslog(LOG_ERR, "Virtual memory exhausted allocating %s", msg);
1393    die(1);
1394}
1395
1396/*
1397 * fmtmsg - format a message into a buffer.  Like snprintf except we
1398 * also specify the length of the output buffer, and we handle
1399 * %m (error message) and %I (IP address) formats.
1400 * Doesn't do floating-point formats.
1401 * Returns the number of chars put into buf.
1402 */
1403int
1404fmtmsg(char *buf, int buflen, char *fmt, ...)
1405{
1406    va_list args;
1407    int n;
1408
1409    va_start(args, fmt);
1410    n = vfmtmsg(buf, buflen, fmt, args);
1411    va_end(args);
1412    return n;
1413}
1414
1415/*
1416 * vfmtmsg - like fmtmsg, takes a va_list instead of a list of args.
1417 */
1418#define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
1419
1420int
1421vfmtmsg(buf, buflen, fmt, args)
1422    char *buf;
1423    int buflen;
1424    char *fmt;
1425    va_list args;
1426{
1427    int c, i, n;
1428    int width, prec, fillch;
1429    int base, len, neg, quoted;
1430    unsigned long val = 0;
1431    char *str, *f, *buf0;
1432    unsigned char *p;
1433    char num[32];
1434    time_t t;
1435    static char hexchars[] = "0123456789abcdef";
1436
1437    buf0 = buf;
1438    --buflen;
1439    while (buflen > 0) {
1440	for (f = fmt; *f != '%' && *f != 0; ++f)
1441	    ;
1442	if (f > fmt) {
1443	    len = f - fmt;
1444	    if (len > buflen)
1445		len = buflen;
1446	    memcpy(buf, fmt, len);
1447	    buf += len;
1448	    buflen -= len;
1449	    fmt = f;
1450	}
1451	if (*fmt == 0)
1452	    break;
1453	c = *++fmt;
1454	width = prec = 0;
1455	fillch = ' ';
1456	if (c == '0') {
1457	    fillch = '0';
1458	    c = *++fmt;
1459	}
1460	if (c == '*') {
1461	    width = va_arg(args, int);
1462	    c = *++fmt;
1463	} else {
1464	    while (isdigit(c)) {
1465		width = width * 10 + c - '0';
1466		c = *++fmt;
1467	    }
1468	}
1469	if (c == '.') {
1470	    c = *++fmt;
1471	    if (c == '*') {
1472		prec = va_arg(args, int);
1473		c = *++fmt;
1474	    } else {
1475		while (isdigit(c)) {
1476		    prec = prec * 10 + c - '0';
1477		    c = *++fmt;
1478		}
1479	    }
1480	}
1481	str = 0;
1482	base = 0;
1483	neg = 0;
1484	++fmt;
1485	switch (c) {
1486	case 'd':
1487	    i = va_arg(args, int);
1488	    if (i < 0) {
1489		neg = 1;
1490		val = -i;
1491	    } else
1492		val = i;
1493	    base = 10;
1494	    break;
1495	case 'o':
1496	    val = va_arg(args, unsigned int);
1497	    base = 8;
1498	    break;
1499	case 'x':
1500	    val = va_arg(args, unsigned int);
1501	    base = 16;
1502	    break;
1503	case 'p':
1504	    val = (unsigned long) va_arg(args, void *);
1505	    base = 16;
1506	    neg = 2;
1507	    break;
1508	case 's':
1509	    str = va_arg(args, char *);
1510	    break;
1511	case 'c':
1512	    num[0] = va_arg(args, int);
1513	    num[1] = 0;
1514	    str = num;
1515	    break;
1516	case 'm':
1517	    str = strerror(errno);
1518	    break;
1519	case 'I':
1520	    str = ip_ntoa(va_arg(args, u_int32_t));
1521	    break;
1522	case 't':
1523	    time(&t);
1524	    str = ctime(&t);
1525	    str += 4;		/* chop off the day name */
1526	    str[15] = 0;	/* chop off year and newline */
1527	    break;
1528	case 'v':		/* "visible" string */
1529	case 'q':		/* quoted string */
1530	    quoted = c == 'q';
1531	    p = va_arg(args, unsigned char *);
1532	    if (fillch == '0' && prec > 0) {
1533		n = prec;
1534	    } else {
1535		n = strlen((char *)p);
1536		if (prec > 0 && prec < n)
1537		    n = prec;
1538	    }
1539	    while (n > 0 && buflen > 0) {
1540		c = *p++;
1541		--n;
1542		if (!quoted && c >= 0x80) {
1543		    OUTCHAR('M');
1544		    OUTCHAR('-');
1545		    c -= 0x80;
1546		}
1547		if (quoted && (c == '"' || c == '\\'))
1548		    OUTCHAR('\\');
1549		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
1550		    if (quoted) {
1551			OUTCHAR('\\');
1552			switch (c) {
1553			case '\t':	OUTCHAR('t');	break;
1554			case '\n':	OUTCHAR('n');	break;
1555			case '\b':	OUTCHAR('b');	break;
1556			case '\f':	OUTCHAR('f');	break;
1557			default:
1558			    OUTCHAR('x');
1559			    OUTCHAR(hexchars[c >> 4]);
1560			    OUTCHAR(hexchars[c & 0xf]);
1561			}
1562		    } else {
1563			if (c == '\t')
1564			    OUTCHAR(c);
1565			else {
1566			    OUTCHAR('^');
1567			    OUTCHAR(c ^ 0x40);
1568			}
1569		    }
1570		} else
1571		    OUTCHAR(c);
1572	    }
1573	    continue;
1574	default:
1575	    *buf++ = '%';
1576	    if (c != '%')
1577		--fmt;		/* so %z outputs %z etc. */
1578	    --buflen;
1579	    continue;
1580	}
1581	if (base != 0) {
1582	    str = num + sizeof(num);
1583	    *--str = 0;
1584	    while (str > num + neg) {
1585		*--str = hexchars[val % base];
1586		val = val / base;
1587		if (--prec <= 0 && val == 0)
1588		    break;
1589	    }
1590	    switch (neg) {
1591	    case 1:
1592		*--str = '-';
1593		break;
1594	    case 2:
1595		*--str = 'x';
1596		*--str = '0';
1597		break;
1598	    }
1599	    len = num + sizeof(num) - 1 - str;
1600	} else {
1601	    len = strlen(str);
1602	    if (prec > 0 && len > prec)
1603		len = prec;
1604	}
1605	if (width > 0) {
1606	    if (width > buflen)
1607		width = buflen;
1608	    if ((n = width - len) > 0) {
1609		buflen -= n;
1610		for (; n > 0; --n)
1611		    *buf++ = fillch;
1612	    }
1613	}
1614	if (len > buflen)
1615	    len = buflen;
1616	memcpy(buf, str, len);
1617	buf += len;
1618	buflen -= len;
1619    }
1620    *buf = 0;
1621    return buf - buf0;
1622}
1623
1624/*
1625 * script_setenv - set an environment variable value to be used
1626 * for scripts that we run (e.g. ip-up, auth-up, etc.)
1627 */
1628void
1629script_setenv(var, value)
1630    char *var, *value;
1631{
1632    int vl = strlen(var);
1633    int i;
1634    char *p, *newstring;
1635
1636    if (asprintf(&newstring, "%s=%s", var, value) == -1)
1637	novm("script_setenv");
1638
1639    /* check if this variable is already set */
1640    if (script_env != 0) {
1641	for (i = 0; (p = script_env[i]) != 0; ++i) {
1642	    if (strncmp(p, var, vl) == 0 && p[vl] == '=') {
1643		free(p);
1644		script_env[i] = newstring;
1645		return;
1646	    }
1647	}
1648    } else {
1649	i = 0;
1650	script_env = (char **) calloc(16, sizeof(char *));
1651	if (script_env == 0)
1652	    novm("script_setenv");
1653	s_env_nalloc = 16;
1654    }
1655
1656    /* reallocate script_env with more space if needed */
1657    if (i + 1 >= s_env_nalloc) {
1658	int new_n = i + 17;
1659	char **newenv = reallocarray(script_env,
1660	    new_n, sizeof(char *));
1661	if (newenv == 0)
1662	    novm("script_setenv");
1663	script_env = newenv;
1664	s_env_nalloc = new_n;
1665    }
1666
1667    script_env[i] = newstring;
1668    script_env[i+1] = 0;
1669}
1670