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