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