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