1 /*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <netinet/in.h> 33 #include <netinet/in_systm.h> 34 #include <netinet/ip.h> 35 #include <sys/un.h> 36 #include <sys/socket.h> 37 #include <net/route.h> 38 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <paths.h> 42 #include <signal.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <sys/time.h> 47 #include <termios.h> 48 #include <unistd.h> 49 #include <sys/stat.h> 50 51 #ifndef NONAT 52 #ifdef LOCALNAT 53 #include "alias.h" 54 #else 55 #include <alias.h> 56 #endif 57 #endif 58 59 #include "layer.h" 60 #include "probe.h" 61 #include "mbuf.h" 62 #include "log.h" 63 #include "defs.h" 64 #include "id.h" 65 #include "timer.h" 66 #include "fsm.h" 67 #include "lqr.h" 68 #include "hdlc.h" 69 #include "lcp.h" 70 #include "ccp.h" 71 #include "iplist.h" 72 #include "throughput.h" 73 #include "slcompress.h" 74 #include "ncpaddr.h" 75 #include "ipcp.h" 76 #include "filter.h" 77 #include "descriptor.h" 78 #include "link.h" 79 #include "mp.h" 80 #ifndef NORADIUS 81 #include "radius.h" 82 #endif 83 #include "ipv6cp.h" 84 #include "ncp.h" 85 #include "bundle.h" 86 #include "auth.h" 87 #include "systems.h" 88 #include "sig.h" 89 #include "main.h" 90 #include "server.h" 91 #include "prompt.h" 92 #include "chat.h" 93 #include "chap.h" 94 #include "cbcp.h" 95 #include "datalink.h" 96 #include "iface.h" 97 98 #ifndef O_NONBLOCK 99 #ifdef O_NDELAY 100 #define O_NONBLOCK O_NDELAY 101 #endif 102 #endif 103 104 static void DoLoop(struct bundle *); 105 static void TerminalStop(int); 106 107 static struct bundle *SignalBundle; 108 static struct prompt *SignalPrompt; 109 110 void 111 Cleanup(int excode) 112 { 113 SignalBundle->CleaningUp = 1; 114 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 115 } 116 117 void 118 AbortProgram(int excode) 119 { 120 if (SignalBundle) 121 server_Close(SignalBundle); 122 log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 123 if (SignalBundle) { 124 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 125 bundle_Destroy(SignalBundle); 126 } 127 log_Close(); 128 exit(excode); 129 } 130 131 static void 132 CloseConnection(int signo) 133 { 134 /* NOTE, these are manual, we've done a setsid() */ 135 sig_signal(SIGINT, SIG_IGN); 136 log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 137 bundle_Down(SignalBundle, CLOSE_STAYDOWN); 138 sig_signal(SIGINT, CloseConnection); 139 } 140 141 static void 142 CloseSession(int signo) 143 { 144 log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 145 Cleanup(EX_TERM); 146 } 147 148 static pid_t BGPid = 0; 149 150 static void 151 KillChild(int signo) 152 { 153 signal(signo, SIG_IGN); 154 log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 155 kill(BGPid, SIGINT); 156 } 157 158 static void 159 TerminalCont(int signo) 160 { 161 signal(SIGCONT, SIG_DFL); 162 prompt_Continue(SignalPrompt); 163 } 164 165 static void 166 TerminalStop(int signo) 167 { 168 prompt_Suspend(SignalPrompt); 169 signal(SIGCONT, TerminalCont); 170 raise(SIGSTOP); 171 } 172 173 static void 174 BringDownServer(int signo) 175 { 176 /* Drops all child prompts too ! */ 177 if (server_Close(SignalBundle)) 178 log_Printf(LogPHASE, "Closed server socket\n"); 179 } 180 181 static void 182 RestartServer(int signo) 183 { 184 /* Drops all child prompts and re-opens the socket */ 185 server_Reopen(SignalBundle); 186 } 187 188 static void 189 Usage(void) 190 { 191 fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |" 192 " -dedicated | -ddial | -interactive]" 193 #ifndef NOALIAS 194 " [-nat]" 195 #endif 196 " [-quiet] [-unit N] [system ...]\n"); 197 exit(EX_START); 198 } 199 200 struct switches { 201 unsigned nat : 1; 202 unsigned fg : 1; 203 unsigned quiet : 1; 204 int mode; 205 int unit; 206 }; 207 208 static int 209 ProcessArgs(int argc, char **argv, struct switches *sw) 210 { 211 int optc, newmode, arg; 212 char *cp; 213 214 optc = 0; 215 memset(sw, '\0', sizeof *sw); 216 sw->mode = PHYS_INTERACTIVE; 217 sw->unit = -1; 218 219 for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 220 cp = argv[arg] + 1; 221 newmode = Nam2mode(cp); 222 switch (newmode) { 223 case PHYS_NONE: 224 if (strcmp(cp, "nat") == 0) { 225 #ifdef NONAT 226 log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 227 #else 228 sw->nat = 1; 229 #endif 230 optc--; /* this option isn't exclusive */ 231 } else if (strcmp(cp, "alias") == 0) { 232 #ifdef NONAT 233 log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 234 fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 235 #else 236 log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 237 fprintf(stderr, "%s is deprecated\n", argv[arg]); 238 sw->nat = 1; 239 #endif 240 optc--; /* this option isn't exclusive */ 241 } else if (strncmp(cp, "unit", 4) == 0) { 242 optc--; /* this option isn't exclusive */ 243 if (cp[4] == '\0') { 244 optc--; /* nor is the argument */ 245 if (++arg == argc) { 246 fprintf(stderr, "-unit: Expected unit number\n"); 247 Usage(); 248 } else 249 sw->unit = atoi(argv[arg]); 250 } else 251 sw->unit = atoi(cp + 4); 252 } else if (strcmp(cp, "quiet") == 0) { 253 sw->quiet = 1; 254 optc--; /* this option isn't exclusive */ 255 } else 256 Usage(); 257 break; 258 259 case PHYS_ALL: 260 Usage(); 261 break; 262 263 default: 264 sw->mode = newmode; 265 if (newmode == PHYS_FOREGROUND) 266 sw->fg = 1; 267 } 268 } 269 270 if (optc > 1) { 271 fprintf(stderr, "You may specify only one mode.\n"); 272 exit(EX_START); 273 } 274 275 if (sw->mode == PHYS_AUTO && arg == argc) { 276 fprintf(stderr, "A system must be specified in auto mode.\n"); 277 exit(EX_START); 278 } 279 280 return arg; /* Don't SetLabel yet ! */ 281 } 282 283 static void 284 CheckLabel(const char *label, struct prompt *prompt, int mode) 285 { 286 const char *err; 287 288 if ((err = system_IsValid(label, prompt, mode)) != NULL) { 289 fprintf(stderr, "%s: %s\n", label, err); 290 if (mode == PHYS_DIRECT) 291 log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 292 label, err); 293 log_Close(); 294 exit(1); 295 } 296 } 297 298 299 int 300 main(int argc, char **argv) 301 { 302 char *name; 303 const char *lastlabel; 304 int arg, f, holdfd[3], label; 305 struct bundle *bundle; 306 struct prompt *prompt; 307 struct switches sw; 308 309 probe_Init(); 310 311 /* 312 * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 313 * STDERR_FILENO are always open. These are closed before DoLoop(), 314 * but *after* we've avoided the possibility of erroneously closing 315 * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 316 */ 317 if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 318 fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 319 return 2; 320 } 321 for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 322 holdfd[f] = dup(holdfd[0]); 323 324 name = strrchr(argv[0], '/'); 325 log_Open(name ? name + 1 : argv[0]); 326 327 #ifndef NONAT 328 PacketAliasInit(); 329 #endif 330 label = ProcessArgs(argc, argv, &sw); 331 332 /* 333 * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 334 * output occasionally.... I must find the real reason some time. To 335 * display the dodgy behaviour, comment out this bit, make yourself a large 336 * routing table and then run ppp in interactive mode. The `show route' 337 * command will drop chunks of data !!! 338 */ 339 if (sw.mode == PHYS_INTERACTIVE) { 340 close(STDIN_FILENO); 341 if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 342 fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 343 return 2; 344 } 345 } 346 347 /* Allow output for the moment (except in direct mode) */ 348 if (sw.mode == PHYS_DIRECT) 349 prompt = NULL; 350 else 351 SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 352 353 ID0init(); 354 if (ID0realuid() != 0) { 355 char conf[200], *ptr; 356 357 snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 358 do { 359 struct stat sb; 360 361 if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 362 log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 363 conf); 364 return -1; 365 } 366 ptr = conf + strlen(conf)-2; 367 while (ptr > conf && *ptr != '/') 368 *ptr-- = '\0'; 369 } while (ptr >= conf); 370 } 371 372 if (label < argc) 373 for (arg = label; arg < argc; arg++) 374 CheckLabel(argv[arg], prompt, sw.mode); 375 else 376 CheckLabel("default", prompt, sw.mode); 377 378 if (!sw.quiet) 379 prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 380 381 if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 382 return EX_START; 383 384 /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 385 386 if (prompt) { 387 prompt->bundle = bundle; /* couldn't do it earlier */ 388 if (!sw.quiet) 389 prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 390 } 391 SignalBundle = bundle; 392 bundle->NatEnabled = sw.nat; 393 if (sw.nat) 394 bundle->cfg.opt |= OPT_IFACEALIAS; 395 396 if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 397 prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 398 399 sig_signal(SIGHUP, CloseSession); 400 sig_signal(SIGTERM, CloseSession); 401 sig_signal(SIGINT, CloseConnection); 402 sig_signal(SIGQUIT, CloseSession); 403 sig_signal(SIGALRM, SIG_IGN); 404 signal(SIGPIPE, SIG_IGN); 405 406 if (sw.mode == PHYS_INTERACTIVE) 407 sig_signal(SIGTSTP, TerminalStop); 408 409 sig_signal(SIGUSR1, RestartServer); 410 sig_signal(SIGUSR2, BringDownServer); 411 412 lastlabel = argv[argc - 1]; 413 for (arg = label; arg < argc; arg++) { 414 /* In case we use LABEL or ``set enddisc label'' */ 415 bundle_SetLabel(bundle, lastlabel); 416 system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 417 } 418 419 if (label < argc) 420 /* In case the last label did a ``load'' */ 421 bundle_SetLabel(bundle, lastlabel); 422 423 if (sw.mode == PHYS_AUTO && 424 ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { 425 prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 426 "in auto mode.\n"); 427 AbortProgram(EX_START); 428 } 429 430 if (sw.mode != PHYS_INTERACTIVE) { 431 if (sw.mode != PHYS_DIRECT) { 432 if (!sw.fg) { 433 int bgpipe[2]; 434 pid_t bgpid; 435 436 if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 437 log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 438 AbortProgram(EX_SOCK); 439 } 440 441 bgpid = fork(); 442 if (bgpid == -1) { 443 log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 444 AbortProgram(EX_SOCK); 445 } 446 447 if (bgpid) { 448 char c = EX_NORMAL; 449 int ret; 450 451 if (sw.mode == PHYS_BACKGROUND) { 452 close(bgpipe[1]); 453 BGPid = bgpid; 454 /* If we get a signal, kill the child */ 455 signal(SIGHUP, KillChild); 456 signal(SIGTERM, KillChild); 457 signal(SIGINT, KillChild); 458 signal(SIGQUIT, KillChild); 459 460 /* Wait for our child to close its pipe before we exit */ 461 while ((ret = read(bgpipe[0], &c, 1)) == 1) { 462 switch (c) { 463 case EX_NORMAL: 464 if (!sw.quiet) { 465 prompt_Printf(prompt, "PPP enabled\n"); 466 log_Printf(LogPHASE, "Parent: PPP enabled\n"); 467 } 468 break; 469 case EX_REDIAL: 470 if (!sw.quiet) 471 prompt_Printf(prompt, "Attempting redial\n"); 472 continue; 473 case EX_RECONNECT: 474 if (!sw.quiet) 475 prompt_Printf(prompt, "Attempting reconnect\n"); 476 continue; 477 default: 478 prompt_Printf(prompt, "Child failed (%s)\n", 479 ex_desc((int)c)); 480 log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 481 ex_desc((int) c)); 482 } 483 break; 484 } 485 if (ret != 1) { 486 prompt_Printf(prompt, "Child exit, no status.\n"); 487 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 488 } 489 close(bgpipe[0]); 490 } 491 return c; 492 } else if (sw.mode == PHYS_BACKGROUND) { 493 close(bgpipe[0]); 494 bundle->notify.fd = bgpipe[1]; 495 } 496 497 bundle_ChangedPID(bundle); 498 bundle_LockTun(bundle); /* we have a new pid */ 499 } 500 501 /* -auto, -dedicated, -ddial, -foreground & -background */ 502 prompt_Destroy(prompt, 0); 503 close(STDOUT_FILENO); 504 close(STDERR_FILENO); 505 close(STDIN_FILENO); 506 if (!sw.fg) 507 setsid(); 508 } else { 509 /* -direct - STDIN_FILENO gets used by physical_Open */ 510 prompt_TtyInit(NULL); 511 close(STDOUT_FILENO); 512 close(STDERR_FILENO); 513 } 514 } else { 515 /* -interactive */ 516 close(STDERR_FILENO); 517 prompt_TtyInit(prompt); 518 prompt_TtyCommandMode(prompt); 519 prompt_Required(prompt); 520 } 521 522 /* We can get rid of these now */ 523 for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 524 close(holdfd[f]); 525 526 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 527 DoLoop(bundle); 528 AbortProgram(EX_NORMAL); 529 530 return EX_NORMAL; 531 } 532 533 static void 534 DoLoop(struct bundle *bundle) 535 { 536 fd_set *rfds, *wfds, *efds; 537 int i, nfds, nothing_done; 538 539 if ((rfds = mkfdset()) == NULL) { 540 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 541 return; 542 } 543 544 if ((wfds = mkfdset()) == NULL) { 545 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 546 free(rfds); 547 return; 548 } 549 550 if ((efds = mkfdset()) == NULL) { 551 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 552 free(rfds); 553 free(wfds); 554 return; 555 } 556 557 for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 558 nfds = 0; 559 zerofdset(rfds); 560 zerofdset(wfds); 561 zerofdset(efds); 562 563 /* All our datalinks, the tun device and the MP socket */ 564 descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 565 566 /* All our prompts and the diagnostic socket */ 567 descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 568 569 bundle_CleanDatalinks(bundle); 570 if (bundle_IsDead(bundle)) 571 /* Don't select - we'll be here forever */ 572 break; 573 574 /* 575 * It's possible that we've had a signal since we last checked. If 576 * we don't check again before calling select(), we may end up stuck 577 * after having missed the event.... sig_Handle() tries to be as 578 * quick as possible if nothing is likely to have happened. 579 * This is only really likely if we block in open(... O_NONBLOCK) 580 * which will happen with a misconfigured device. 581 */ 582 if (sig_Handle()) 583 continue; 584 585 i = select(nfds, rfds, wfds, efds, NULL); 586 587 if (i < 0 && errno != EINTR) { 588 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 589 if (log_IsKept(LogTIMER)) { 590 struct timeval t; 591 592 for (i = 0; i <= nfds; i++) { 593 if (FD_ISSET(i, rfds)) { 594 log_Printf(LogTIMER, "Read set contains %d\n", i); 595 FD_CLR(i, rfds); 596 t.tv_sec = t.tv_usec = 0; 597 if (select(nfds, rfds, wfds, efds, &t) != -1) { 598 log_Printf(LogTIMER, "The culprit !\n"); 599 break; 600 } 601 } 602 if (FD_ISSET(i, wfds)) { 603 log_Printf(LogTIMER, "Write set contains %d\n", i); 604 FD_CLR(i, wfds); 605 t.tv_sec = t.tv_usec = 0; 606 if (select(nfds, rfds, wfds, efds, &t) != -1) { 607 log_Printf(LogTIMER, "The culprit !\n"); 608 break; 609 } 610 } 611 if (FD_ISSET(i, efds)) { 612 log_Printf(LogTIMER, "Error set contains %d\n", i); 613 FD_CLR(i, efds); 614 t.tv_sec = t.tv_usec = 0; 615 if (select(nfds, rfds, wfds, efds, &t) != -1) { 616 log_Printf(LogTIMER, "The culprit !\n"); 617 break; 618 } 619 } 620 } 621 } 622 break; 623 } 624 625 log_Printf(LogTIMER, "Select returns %d\n", i); 626 627 sig_Handle(); 628 629 if (i <= 0) 630 continue; 631 632 for (i = 0; i <= nfds; i++) 633 if (FD_ISSET(i, efds)) { 634 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 635 /* We deal gracefully with link descriptor exceptions */ 636 if (!bundle_Exception(bundle, i)) { 637 log_Printf(LogERROR, "Exception cannot be handled !\n"); 638 break; 639 } 640 } 641 642 if (i <= nfds) 643 break; 644 645 nothing_done = 1; 646 647 if (descriptor_IsSet(&server.desc, rfds)) { 648 descriptor_Read(&server.desc, bundle, rfds); 649 nothing_done = 0; 650 } 651 652 if (descriptor_IsSet(&bundle->desc, rfds)) { 653 descriptor_Read(&bundle->desc, bundle, rfds); 654 nothing_done = 0; 655 } 656 657 if (descriptor_IsSet(&bundle->desc, wfds)) 658 if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { 659 /* 660 * This is disastrous. The OS has told us that something is 661 * writable, and all our write()s have failed. Rather than 662 * going back immediately to do our UpdateSet()s and select(), 663 * we sleep for a bit to avoid gobbling up all cpu time. 664 */ 665 struct timeval t; 666 667 t.tv_sec = 0; 668 t.tv_usec = 100000; 669 select(0, NULL, NULL, NULL, &t); 670 } 671 } 672 673 log_Printf(LogDEBUG, "DoLoop done.\n"); 674 } 675