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 *
| 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 59104 2000-04-09 18:27:08Z brian $
| 20 * $FreeBSD: head/usr.sbin/ppp/main.c 66898 2000-10-09 21:18:23Z 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 server_Close(SignalBundle); 166} 167 168static void 169Usage(void) 170{ 171 fprintf(stderr, 172 "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 173#ifndef NOALIAS 174 " [-nat]" 175#endif 176 " [-quiet] [-unit N] [system ...]\n"); 177 exit(EX_START); 178} 179 180struct switches { 181 unsigned nat : 1; 182 unsigned fg : 1; 183 unsigned quiet : 1; 184 int mode; 185 int unit; 186}; 187 188static int 189ProcessArgs(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 263static void 264CheckLabel(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 279int 280main(int argc, char **argv) 281{ 282 char *name; 283 const char *lastlabel;
| 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 server_Close(SignalBundle); 166} 167 168static void 169Usage(void) 170{ 171 fprintf(stderr, 172 "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 173#ifndef NOALIAS 174 " [-nat]" 175#endif 176 " [-quiet] [-unit N] [system ...]\n"); 177 exit(EX_START); 178} 179 180struct switches { 181 unsigned nat : 1; 182 unsigned fg : 1; 183 unsigned quiet : 1; 184 int mode; 185 int unit; 186}; 187 188static int 189ProcessArgs(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 263static void 264CheckLabel(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 279int 280main(int argc, char **argv) 281{ 282 char *name; 283 const char *lastlabel;
|
284 int nfds, label, arg;
| 284 int label, arg;
|
285 struct bundle *bundle; 286 struct prompt *prompt; 287 struct switches sw; 288
| 285 struct bundle *bundle; 286 struct prompt *prompt; 287 struct switches sw; 288
|
289 nfds = getdtablesize(); 290 if (nfds >= FD_SETSIZE) 291 /* 292 * If we've got loads of file descriptors, make sure they're all 293 * closed. If they aren't, we may end up with a seg fault when our 294 * `fd_set's get too big when select()ing ! 295 */ 296 while (--nfds > 2) 297 close(nfds); 298
| |
299 name = strrchr(argv[0], '/'); 300 log_Open(name ? name + 1 : argv[0]); 301 302#ifndef NONAT 303 PacketAliasInit(); 304#endif 305 label = ProcessArgs(argc, argv, &sw); 306 307 /* 308 * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 309 * output occasionally.... I must find the real reason some time. To 310 * display the dodgy behaviour, comment out this bit, make yourself a large 311 * routing table and then run ppp in interactive mode. The `show route' 312 * command will drop chunks of data !!! 313 */ 314 if (sw.mode == PHYS_INTERACTIVE) { 315 close(STDIN_FILENO); 316 if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 317 fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 318 return 2; 319 } 320 } 321 322 /* Allow output for the moment (except in direct mode) */ 323 if (sw.mode == PHYS_DIRECT) 324 prompt = NULL; 325 else 326 SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 327 328 ID0init(); 329 if (ID0realuid() != 0) { 330 char conf[200], *ptr; 331 332 snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 333 do { 334 struct stat sb; 335 336 if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 337 log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 338 conf); 339 return -1; 340 } 341 ptr = conf + strlen(conf)-2; 342 while (ptr > conf && *ptr != '/') 343 *ptr-- = '\0'; 344 } while (ptr >= conf); 345 } 346 347 if (label < argc) 348 for (arg = label; arg < argc; arg++) 349 CheckLabel(argv[arg], prompt, sw.mode); 350 else 351 CheckLabel("default", prompt, sw.mode); 352 353 if (!sw.quiet) 354 prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 355 356 if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 357 return EX_START; 358 359 /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 360 361 if (prompt) { 362 prompt->bundle = bundle; /* couldn't do it earlier */ 363 if (!sw.quiet) 364 prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 365 } 366 SignalBundle = bundle; 367 bundle->NatEnabled = sw.nat; 368 if (sw.nat) 369 bundle->cfg.opt |= OPT_IFACEALIAS; 370 371 if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 372 prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 373 374 sig_signal(SIGHUP, CloseSession); 375 sig_signal(SIGTERM, CloseSession); 376 sig_signal(SIGINT, CloseConnection); 377 sig_signal(SIGQUIT, CloseSession); 378 sig_signal(SIGALRM, SIG_IGN); 379 signal(SIGPIPE, SIG_IGN); 380 381 if (sw.mode == PHYS_INTERACTIVE) 382 sig_signal(SIGTSTP, TerminalStop); 383 384 sig_signal(SIGUSR2, BringDownServer); 385 386 lastlabel = argv[argc - 1]; 387 for (arg = label; arg < argc; arg++) { 388 /* In case we use LABEL or ``set enddisc label'' */ 389 bundle_SetLabel(bundle, lastlabel); 390 system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 391 } 392 393 if (label < argc) 394 /* In case the last label did a ``load'' */ 395 bundle_SetLabel(bundle, lastlabel); 396 397 if (sw.mode == PHYS_AUTO && 398 bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 399 prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 400 "in auto mode.\n"); 401 AbortProgram(EX_START); 402 } 403 404 if (sw.mode != PHYS_INTERACTIVE) { 405 if (sw.mode != PHYS_DIRECT) { 406 if (!sw.fg) { 407 int bgpipe[2]; 408 pid_t bgpid; 409 410 if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 411 log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 412 AbortProgram(EX_SOCK); 413 } 414 415 bgpid = fork(); 416 if (bgpid == -1) { 417 log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 418 AbortProgram(EX_SOCK); 419 } 420 421 if (bgpid) { 422 char c = EX_NORMAL; 423 int ret; 424 425 if (sw.mode == PHYS_BACKGROUND) { 426 close(bgpipe[1]); 427 BGPid = bgpid; 428 /* If we get a signal, kill the child */ 429 signal(SIGHUP, KillChild); 430 signal(SIGTERM, KillChild); 431 signal(SIGINT, KillChild); 432 signal(SIGQUIT, KillChild); 433 434 /* Wait for our child to close its pipe before we exit */ 435 while ((ret = read(bgpipe[0], &c, 1)) == 1) { 436 switch (c) { 437 case EX_NORMAL: 438 prompt_Printf(prompt, "PPP enabled\n"); 439 log_Printf(LogPHASE, "Parent: PPP enabled\n"); 440 break; 441 case EX_REDIAL: 442 if (!sw.quiet) 443 prompt_Printf(prompt, "Attempting redial\n"); 444 continue; 445 case EX_RECONNECT: 446 if (!sw.quiet) 447 prompt_Printf(prompt, "Attempting reconnect\n"); 448 continue; 449 default: 450 prompt_Printf(prompt, "Child failed (%s)\n", 451 ex_desc((int)c)); 452 log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 453 ex_desc((int) c)); 454 } 455 break; 456 } 457 if (ret != 1) { 458 prompt_Printf(prompt, "Child exit, no status.\n"); 459 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 460 } 461 close(bgpipe[0]); 462 } 463 return c; 464 } else if (sw.mode == PHYS_BACKGROUND) { 465 close(bgpipe[0]); 466 bundle->notify.fd = bgpipe[1]; 467 } 468 469 bundle_ChangedPID(bundle); 470 bundle_LockTun(bundle); /* we have a new pid */ 471 } 472 473 /* -auto, -dedicated, -ddial, -foreground & -background */ 474 prompt_Destroy(prompt, 0); 475 close(STDOUT_FILENO); 476 close(STDERR_FILENO); 477 close(STDIN_FILENO); 478 if (!sw.fg) 479 setsid(); 480 } else { 481 /* -direct - STDIN_FILENO gets used by physical_Open */ 482 prompt_TtyInit(NULL); 483 close(STDOUT_FILENO); 484 close(STDERR_FILENO); 485 } 486 } else { 487 /* -interactive */ 488 close(STDERR_FILENO); 489 prompt_TtyInit(prompt); 490 prompt_TtyCommandMode(prompt); 491 prompt_Required(prompt); 492 } 493 494 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 495 DoLoop(bundle); 496 AbortProgram(EX_NORMAL); 497 498 return EX_NORMAL; 499} 500 501static void 502DoLoop(struct bundle *bundle) 503{
| 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 491static void 492DoLoop(struct bundle *bundle) 493{
|
504 fd_set rfds, wfds, efds;
| 494 fd_set *rfds, *wfds, *efds;
|
505 int i, nfds, nothing_done; 506 struct probe probe; 507 508 probe_Init(&probe); 509
| 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
|
510 for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 511 nfds = 0;
| 518 for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 519 nfds = 0;
|
512 FD_ZERO(&rfds); 513 FD_ZERO(&wfds); 514 FD_ZERO(&efds);
| 520 zerofdset(rfds); 521 zerofdset(wfds); 522 zerofdset(efds);
|
515 516 /* All our datalinks, the tun device and the MP socket */
| 523 524 /* All our datalinks, the tun device and the MP socket */
|
517 descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds);
| 525 descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);
|
518 519 /* All our prompts and the diagnostic socket */
| 526 527 /* All our prompts and the diagnostic socket */
|
520 descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds);
| 528 descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);
|
521 522 bundle_CleanDatalinks(bundle); 523 if (bundle_IsDead(bundle)) 524 /* Don't select - we'll be here forever */ 525 break; 526 527 /* 528 * It's possible that we've had a signal since we last checked. If 529 * we don't check again before calling select(), we may end up stuck 530 * after having missed the event.... sig_Handle() tries to be as 531 * quick as possible if nothing is likely to have happened. 532 * This is only really likely if we block in open(... O_NONBLOCK) 533 * which will happen with a misconfigured device. 534 */ 535 if (sig_Handle()) 536 continue; 537
| 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
|
538 i = select(nfds, &rfds, &wfds, &efds, NULL);
| 546 i = select(nfds, rfds, wfds, efds, NULL);
|
539 540 if (i < 0 && errno != EINTR) { 541 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 542 if (log_IsKept(LogTIMER)) { 543 struct timeval t; 544 545 for (i = 0; i <= nfds; i++) {
| 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++) {
|
546 if (FD_ISSET(i, &rfds)) {
| 554 if (FD_ISSET(i, rfds)) {
|
547 log_Printf(LogTIMER, "Read set contains %d\n", i);
| 555 log_Printf(LogTIMER, "Read set contains %d\n", i);
|
548 FD_CLR(i, &rfds);
| 556 FD_CLR(i, rfds);
|
549 t.tv_sec = t.tv_usec = 0;
| 557 t.tv_sec = t.tv_usec = 0;
|
550 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) {
| 558 if (select(nfds, rfds, wfds, efds, &t) != -1) {
|
551 log_Printf(LogTIMER, "The culprit !\n"); 552 break; 553 } 554 }
| 559 log_Printf(LogTIMER, "The culprit !\n"); 560 break; 561 } 562 }
|
555 if (FD_ISSET(i, &wfds)) {
| 563 if (FD_ISSET(i, wfds)) {
|
556 log_Printf(LogTIMER, "Write set contains %d\n", i);
| 564 log_Printf(LogTIMER, "Write set contains %d\n", i);
|
557 FD_CLR(i, &wfds);
| 565 FD_CLR(i, wfds);
|
558 t.tv_sec = t.tv_usec = 0;
| 566 t.tv_sec = t.tv_usec = 0;
|
559 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) {
| 567 if (select(nfds, rfds, wfds, efds, &t) != -1) {
|
560 log_Printf(LogTIMER, "The culprit !\n"); 561 break; 562 } 563 }
| 568 log_Printf(LogTIMER, "The culprit !\n"); 569 break; 570 } 571 }
|
564 if (FD_ISSET(i, &efds)) {
| 572 if (FD_ISSET(i, efds)) {
|
565 log_Printf(LogTIMER, "Error set contains %d\n", i);
| 573 log_Printf(LogTIMER, "Error set contains %d\n", i);
|
566 FD_CLR(i, &efds);
| 574 FD_CLR(i, efds);
|
567 t.tv_sec = t.tv_usec = 0;
| 575 t.tv_sec = t.tv_usec = 0;
|
568 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) {
| 576 if (select(nfds, rfds, wfds, efds, &t) != -1) {
|
569 log_Printf(LogTIMER, "The culprit !\n"); 570 break; 571 } 572 } 573 } 574 } 575 break; 576 } 577 578 log_Printf(LogTIMER, "Select returns %d\n", i); 579 580 sig_Handle(); 581 582 if (i <= 0) 583 continue; 584 585 for (i = 0; i <= nfds; i++)
| 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++)
|
586 if (FD_ISSET(i, &efds)) {
| 594 if (FD_ISSET(i, efds)) {
|
587 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 588 /* We deal gracefully with link descriptor exceptions */ 589 if (!bundle_Exception(bundle, i)) { 590 log_Printf(LogERROR, "Exception cannot be handled !\n"); 591 break; 592 } 593 } 594 595 if (i <= nfds) 596 break; 597 598 nothing_done = 1; 599
| 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
|
600 if (descriptor_IsSet(&server.desc, &rfds)) { 601 descriptor_Read(&server.desc, bundle, &rfds);
| 608 if (descriptor_IsSet(&server.desc, rfds)) { 609 descriptor_Read(&server.desc, bundle, rfds);
|
602 nothing_done = 0; 603 } 604
| 610 nothing_done = 0; 611 } 612
|
605 if (descriptor_IsSet(&bundle->desc, &rfds)) { 606 descriptor_Read(&bundle->desc, bundle, &rfds);
| 613 if (descriptor_IsSet(&bundle->desc, rfds)) { 614 descriptor_Read(&bundle->desc, bundle, rfds);
|
607 nothing_done = 0; 608 } 609
| 615 nothing_done = 0; 616 } 617
|
610 if (descriptor_IsSet(&bundle->desc, &wfds)) 611 if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) {
| 618 if (descriptor_IsSet(&bundle->desc, wfds)) 619 if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) {
|
612 /* 613 * This is disasterous. The OS has told us that something is 614 * writable, and all our write()s have failed. Rather than 615 * going back immediately to do our UpdateSet()s and select(), 616 * we sleep for a bit to avoid gobbling up all cpu time. 617 */ 618 struct timeval t; 619 620 t.tv_sec = 0; 621 t.tv_usec = 100000; 622 select(0, NULL, NULL, NULL, &t); 623 } 624 } 625 626 log_Printf(LogDEBUG, "DoLoop done.\n"); 627}
| 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}
|