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