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