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