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