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