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