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