main.c revision 74687
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 74687 2001-03-23 11:43:22Z 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 prompt_Printf(prompt, "PPP enabled\n"); 438 log_Printf(LogPHASE, "Parent: PPP enabled\n"); 439 break; 440 case EX_REDIAL: 441 if (!sw.quiet) 442 prompt_Printf(prompt, "Attempting redial\n"); 443 continue; 444 case EX_RECONNECT: 445 if (!sw.quiet) 446 prompt_Printf(prompt, "Attempting reconnect\n"); 447 continue; 448 default: 449 prompt_Printf(prompt, "Child failed (%s)\n", 450 ex_desc((int)c)); 451 log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 452 ex_desc((int) c)); 453 } 454 break; 455 } 456 if (ret != 1) { 457 prompt_Printf(prompt, "Child exit, no status.\n"); 458 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 459 } 460 close(bgpipe[0]); 461 } 462 return c; 463 } else if (sw.mode == PHYS_BACKGROUND) { 464 close(bgpipe[0]); 465 bundle->notify.fd = bgpipe[1]; 466 } 467 468 bundle_ChangedPID(bundle); 469 bundle_LockTun(bundle); /* we have a new pid */ 470 } 471 472 /* -auto, -dedicated, -ddial, -foreground & -background */ 473 prompt_Destroy(prompt, 0); 474 close(STDOUT_FILENO); 475 close(STDERR_FILENO); 476 close(STDIN_FILENO); 477 if (!sw.fg) 478 setsid(); 479 } else { 480 /* -direct - STDIN_FILENO gets used by physical_Open */ 481 prompt_TtyInit(NULL); 482 close(STDOUT_FILENO); 483 close(STDERR_FILENO); 484 } 485 } else { 486 /* -interactive */ 487 close(STDERR_FILENO); 488 prompt_TtyInit(prompt); 489 prompt_TtyCommandMode(prompt); 490 prompt_Required(prompt); 491 } 492 493 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 494 DoLoop(bundle); 495 AbortProgram(EX_NORMAL); 496 497 return EX_NORMAL; 498} 499 500static void 501DoLoop(struct bundle *bundle) 502{ 503 fd_set *rfds, *wfds, *efds; 504 int i, nfds, nothing_done; 505 struct probe probe; 506 507 probe_Init(&probe); 508 509 if ((rfds = mkfdset()) == NULL) { 510 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 511 return; 512 } 513 514 if ((wfds = mkfdset()) == NULL) { 515 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 516 free(rfds); 517 return; 518 } 519 520 if ((efds = mkfdset()) == NULL) { 521 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 522 free(rfds); 523 free(wfds); 524 return; 525 } 526 527 for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 528 nfds = 0; 529 zerofdset(rfds); 530 zerofdset(wfds); 531 zerofdset(efds); 532 533 /* All our datalinks, the tun device and the MP socket */ 534 descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 535 536 /* All our prompts and the diagnostic socket */ 537 descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 538 539 bundle_CleanDatalinks(bundle); 540 if (bundle_IsDead(bundle)) 541 /* Don't select - we'll be here forever */ 542 break; 543 544 /* 545 * It's possible that we've had a signal since we last checked. If 546 * we don't check again before calling select(), we may end up stuck 547 * after having missed the event.... sig_Handle() tries to be as 548 * quick as possible if nothing is likely to have happened. 549 * This is only really likely if we block in open(... O_NONBLOCK) 550 * which will happen with a misconfigured device. 551 */ 552 if (sig_Handle()) 553 continue; 554 555 i = select(nfds, rfds, wfds, efds, NULL); 556 557 if (i < 0 && errno != EINTR) { 558 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 559 if (log_IsKept(LogTIMER)) { 560 struct timeval t; 561 562 for (i = 0; i <= nfds; i++) { 563 if (FD_ISSET(i, rfds)) { 564 log_Printf(LogTIMER, "Read set contains %d\n", i); 565 FD_CLR(i, rfds); 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, wfds)) { 573 log_Printf(LogTIMER, "Write set contains %d\n", i); 574 FD_CLR(i, wfds); 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 if (FD_ISSET(i, efds)) { 582 log_Printf(LogTIMER, "Error set contains %d\n", i); 583 FD_CLR(i, efds); 584 t.tv_sec = t.tv_usec = 0; 585 if (select(nfds, rfds, wfds, efds, &t) != -1) { 586 log_Printf(LogTIMER, "The culprit !\n"); 587 break; 588 } 589 } 590 } 591 } 592 break; 593 } 594 595 log_Printf(LogTIMER, "Select returns %d\n", i); 596 597 sig_Handle(); 598 599 if (i <= 0) 600 continue; 601 602 for (i = 0; i <= nfds; i++) 603 if (FD_ISSET(i, efds)) { 604 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 605 /* We deal gracefully with link descriptor exceptions */ 606 if (!bundle_Exception(bundle, i)) { 607 log_Printf(LogERROR, "Exception cannot be handled !\n"); 608 break; 609 } 610 } 611 612 if (i <= nfds) 613 break; 614 615 nothing_done = 1; 616 617 if (descriptor_IsSet(&server.desc, rfds)) { 618 descriptor_Read(&server.desc, bundle, rfds); 619 nothing_done = 0; 620 } 621 622 if (descriptor_IsSet(&bundle->desc, rfds)) { 623 descriptor_Read(&bundle->desc, bundle, rfds); 624 nothing_done = 0; 625 } 626 627 if (descriptor_IsSet(&bundle->desc, wfds)) 628 if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) { 629 /* 630 * This is disasterous. The OS has told us that something is 631 * writable, and all our write()s have failed. Rather than 632 * going back immediately to do our UpdateSet()s and select(), 633 * we sleep for a bit to avoid gobbling up all cpu time. 634 */ 635 struct timeval t; 636 637 t.tv_sec = 0; 638 t.tv_usec = 100000; 639 select(0, NULL, NULL, NULL, &t); 640 } 641 } 642 643 log_Printf(LogDEBUG, "DoLoop done.\n"); 644} 645