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