165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 302764b86aSBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 3275240ed1SBrian Somers #include <netinet/in.h> 33a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h> 34a9f484e5SJordan K. Hubbard #include <netinet/ip.h> 35565e35e5SBrian Somers #include <sys/un.h> 366b457978SBrian Somers #include <sys/socket.h> 376b457978SBrian Somers #include <net/route.h> 3875240ed1SBrian Somers 3975240ed1SBrian Somers #include <errno.h> 4075240ed1SBrian Somers #include <fcntl.h> 4175240ed1SBrian Somers #include <paths.h> 4275240ed1SBrian Somers #include <signal.h> 4375240ed1SBrian Somers #include <stdio.h> 44c0593e34SBrian Somers #include <stdlib.h> 4575240ed1SBrian Somers #include <string.h> 4675240ed1SBrian Somers #include <sys/time.h> 4775240ed1SBrian Somers #include <termios.h> 4875240ed1SBrian Somers #include <unistd.h> 491080ea25SBrian Somers #include <sys/stat.h> 5075240ed1SBrian Somers 5167b072f7SBrian Somers #ifndef NONAT 5210e629b9SBrian Somers #ifdef LOCALNAT 537884358fSBrian Somers #include "alias.h" 5410e629b9SBrian Somers #else 5510e629b9SBrian Somers #include <alias.h> 561595bacdSBrian Somers #endif 571595bacdSBrian Somers #endif 5810e629b9SBrian Somers 595d9e6103SBrian Somers #include "layer.h" 601af29a6eSBrian Somers #include "probe.h" 6175240ed1SBrian Somers #include "mbuf.h" 6275240ed1SBrian Somers #include "log.h" 6375240ed1SBrian Somers #include "defs.h" 645106c671SBrian Somers #include "id.h" 6575240ed1SBrian Somers #include "timer.h" 6675240ed1SBrian Somers #include "fsm.h" 67879ed6faSBrian Somers #include "lqr.h" 68af57ed9fSAtsushi Murai #include "hdlc.h" 69af57ed9fSAtsushi Murai #include "lcp.h" 700053cc58SBrian Somers #include "ccp.h" 7129e275ceSBrian Somers #include "iplist.h" 7229e275ceSBrian Somers #include "throughput.h" 73eaa4df37SBrian Somers #include "slcompress.h" 74af57ed9fSAtsushi Murai #include "ipcp.h" 7584b8a6ebSAtsushi Murai #include "filter.h" 762f786681SBrian Somers #include "descriptor.h" 773b0f8d2eSBrian Somers #include "link.h" 783b0f8d2eSBrian Somers #include "mp.h" 79972a1bcfSBrian Somers #ifndef NORADIUS 80972a1bcfSBrian Somers #include "radius.h" 81972a1bcfSBrian Somers #endif 825828db6dSBrian Somers #include "bundle.h" 831ae349f5Scvs2svn #include "auth.h" 84ed6a16c1SPoul-Henning Kamp #include "systems.h" 85f5ff0f7cSBrian Somers #include "sig.h" 8675240ed1SBrian Somers #include "main.h" 8777ff88adSBrian Somers #include "server.h" 8885b542cfSBrian Somers #include "prompt.h" 89b6dec9f0SBrian Somers #include "chat.h" 90e2ebb036SBrian Somers #include "chap.h" 9192b09558SBrian Somers #include "cbcp.h" 923006ec67SBrian Somers #include "datalink.h" 938fa6ebe4SBrian Somers #include "iface.h" 9453c9f6c0SAtsushi Murai 9553c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 9653c9f6c0SAtsushi Murai #ifdef O_NDELAY 9753c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 9853c9f6c0SAtsushi Murai #endif 9953c9f6c0SAtsushi Murai #endif 100af57ed9fSAtsushi Murai 1010f78c7a7SBrian Somers static void DoLoop(struct bundle *); 10275240ed1SBrian Somers static void TerminalStop(int); 10375240ed1SBrian Somers 10483d1af55SBrian Somers static struct bundle *SignalBundle; 105b6217683SBrian Somers static struct prompt *SignalPrompt; 106c3899f8dSAtsushi Murai 107c3899f8dSAtsushi Murai void 108944f7098SBrian Somers Cleanup(int excode) 109af57ed9fSAtsushi Murai { 110a0cbd833SBrian Somers SignalBundle->CleaningUp = 1; 1119c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1126e4959f0SBrian Somers } 113af57ed9fSAtsushi Murai 1141afedc4bSBrian Somers void 1151afedc4bSBrian Somers AbortProgram(int excode) 1161afedc4bSBrian Somers { 117dd7e2610SBrian Somers server_Close(SignalBundle); 118dd7e2610SBrian Somers log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 1199c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 12068a0f0ccSBrian Somers bundle_Destroy(SignalBundle); 121dd7e2610SBrian Somers log_Close(); 122af57ed9fSAtsushi Murai exit(excode); 123af57ed9fSAtsushi Murai } 124af57ed9fSAtsushi Murai 125af57ed9fSAtsushi Murai static void 126944f7098SBrian Somers CloseConnection(int signo) 127af57ed9fSAtsushi Murai { 128368aee2bSBrian Somers /* NOTE, these are manual, we've done a setsid() */ 129dd7e2610SBrian Somers sig_signal(SIGINT, SIG_IGN); 130dd7e2610SBrian Somers log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 131899011c4SBrian Somers bundle_Down(SignalBundle, CLOSE_STAYDOWN); 132dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 1336d14e2a8SJordan K. Hubbard } 134af57ed9fSAtsushi Murai 135af57ed9fSAtsushi Murai static void 136944f7098SBrian Somers CloseSession(int signo) 137af57ed9fSAtsushi Murai { 138dd7e2610SBrian Somers log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 139af57ed9fSAtsushi Murai Cleanup(EX_TERM); 140af57ed9fSAtsushi Murai } 141c3899f8dSAtsushi Murai 14275b8d283SBrian Somers static pid_t BGPid = 0; 14375b8d283SBrian Somers 14475b8d283SBrian Somers static void 14575b8d283SBrian Somers KillChild(int signo) 14675b8d283SBrian Somers { 147ac37ab22SBrian Somers signal(signo, SIG_IGN); 148dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14975b8d283SBrian Somers kill(BGPid, SIGINT); 15075b8d283SBrian Somers } 15175b8d283SBrian Somers 152c3899f8dSAtsushi Murai static void 153b6e82f33SBrian Somers TerminalCont(int signo) 154c3899f8dSAtsushi Murai { 155f91ad6b0SBrian Somers signal(SIGCONT, SIG_DFL); 156f91ad6b0SBrian Somers prompt_Continue(SignalPrompt); 157c3899f8dSAtsushi Murai } 158c3899f8dSAtsushi Murai 159c3899f8dSAtsushi Murai static void 160944f7098SBrian Somers TerminalStop(int signo) 161c3899f8dSAtsushi Murai { 162f91ad6b0SBrian Somers prompt_Suspend(SignalPrompt); 163f91ad6b0SBrian Somers signal(SIGCONT, TerminalCont); 164f91ad6b0SBrian Somers raise(SIGSTOP); 1654ef16f24SBrian Somers } 1664ef16f24SBrian Somers 1678ea8442cSBrian Somers static void 1688ea8442cSBrian Somers BringDownServer(int signo) 1698ea8442cSBrian Somers { 170b6217683SBrian Somers /* Drops all child prompts too ! */ 17174457d3dSBrian Somers if (server_Close(SignalBundle)) 17274457d3dSBrian Somers log_Printf(LogPHASE, "Closed server socket\n"); 17374457d3dSBrian Somers } 17474457d3dSBrian Somers 17574457d3dSBrian Somers static void 17674457d3dSBrian Somers RestartServer(int signo) 17774457d3dSBrian Somers { 17874457d3dSBrian Somers /* Drops all child prompts and re-opens the socket */ 17974457d3dSBrian Somers server_Reopen(SignalBundle); 1808ea8442cSBrian Somers } 1818ea8442cSBrian Somers 18275240ed1SBrian Somers static void 183b6e82f33SBrian Somers Usage(void) 184af57ed9fSAtsushi Murai { 1859b996792SBrian Somers fprintf(stderr, "Usage: ppp [-auto | -foreground | -background | -direct |" 1869b996792SBrian Somers " -dedicated | -ddial | -interactive]" 187b6e82f33SBrian Somers #ifndef NOALIAS 18867b072f7SBrian Somers " [-nat]" 189b6e82f33SBrian Somers #endif 190c0593e34SBrian Somers " [-quiet] [-unit N] [system ...]\n"); 191af57ed9fSAtsushi Murai exit(EX_START); 192af57ed9fSAtsushi Murai } 193af57ed9fSAtsushi Murai 194c0593e34SBrian Somers struct switches { 195c0593e34SBrian Somers unsigned nat : 1; 196c0593e34SBrian Somers unsigned fg : 1; 197c0593e34SBrian Somers unsigned quiet : 1; 198c0593e34SBrian Somers int mode; 199c0593e34SBrian Somers int unit; 200c0593e34SBrian Somers }; 201c0593e34SBrian Somers 2027cf368ebSBrian Somers static int 203c0593e34SBrian Somers ProcessArgs(int argc, char **argv, struct switches *sw) 204af57ed9fSAtsushi Murai { 2057cf368ebSBrian Somers int optc, newmode, arg; 206af57ed9fSAtsushi Murai char *cp; 207af57ed9fSAtsushi Murai 2087cf368ebSBrian Somers optc = 0; 209c0593e34SBrian Somers memset(sw, '\0', sizeof *sw); 210c0593e34SBrian Somers sw->mode = PHYS_INTERACTIVE; 211c0593e34SBrian Somers sw->unit = -1; 212c0593e34SBrian Somers 2137cf368ebSBrian Somers for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 2147cf368ebSBrian Somers cp = argv[arg] + 1; 21581358fa3SBrian Somers newmode = Nam2mode(cp); 21681358fa3SBrian Somers switch (newmode) { 21781358fa3SBrian Somers case PHYS_NONE: 218c0593e34SBrian Somers if (strcmp(cp, "nat") == 0) { 21967b072f7SBrian Somers #ifdef NONAT 220c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 221615ad4f9SBrian Somers #else 222c0593e34SBrian Somers sw->nat = 1; 223615ad4f9SBrian Somers #endif 2241ae349f5Scvs2svn optc--; /* this option isn't exclusive */ 225c0593e34SBrian Somers } else if (strcmp(cp, "alias") == 0) { 226c0593e34SBrian Somers #ifdef NONAT 227c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 228c0593e34SBrian Somers fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 229c0593e34SBrian Somers #else 230886530abSBrian Somers log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 231886530abSBrian Somers fprintf(stderr, "%s is deprecated\n", argv[arg]); 232c0593e34SBrian Somers sw->nat = 1; 233c0593e34SBrian Somers #endif 234c0593e34SBrian Somers optc--; /* this option isn't exclusive */ 235c0593e34SBrian Somers } else if (strncmp(cp, "unit", 4) == 0) { 2369d06928dSBrian Somers optc--; /* this option isn't exclusive */ 237c0593e34SBrian Somers if (cp[4] == '\0') { 2389d06928dSBrian Somers optc--; /* nor is the argument */ 239c0593e34SBrian Somers if (++arg == argc) { 240c0593e34SBrian Somers fprintf(stderr, "-unit: Expected unit number\n"); 241c0593e34SBrian Somers Usage(); 242c0593e34SBrian Somers } else 243c0593e34SBrian Somers sw->unit = atoi(argv[arg]); 244c0593e34SBrian Somers } else 245c0593e34SBrian Somers sw->unit = atoi(cp + 4); 24667b072f7SBrian Somers } else if (strcmp(cp, "quiet") == 0) { 247c0593e34SBrian Somers sw->quiet = 1; 24867b072f7SBrian Somers optc--; /* this option isn't exclusive */ 249944f7098SBrian Somers } else 250af57ed9fSAtsushi Murai Usage(); 25181358fa3SBrian Somers break; 25281358fa3SBrian Somers 25381358fa3SBrian Somers case PHYS_ALL: 25481358fa3SBrian Somers Usage(); 25581358fa3SBrian Somers break; 25681358fa3SBrian Somers 25781358fa3SBrian Somers default: 258c0593e34SBrian Somers sw->mode = newmode; 259f6a4e748SBrian Somers if (newmode == PHYS_FOREGROUND) 260f6a4e748SBrian Somers sw->fg = 1; 26181358fa3SBrian Somers } 262af57ed9fSAtsushi Murai } 263af57ed9fSAtsushi Murai 264af57ed9fSAtsushi Murai if (optc > 1) { 26585602e52SBrian Somers fprintf(stderr, "You may specify only one mode.\n"); 2661ae349f5Scvs2svn exit(EX_START); 2671ae349f5Scvs2svn } 2681ae349f5Scvs2svn 269c0593e34SBrian Somers if (sw->mode == PHYS_AUTO && arg == argc) { 2707cf368ebSBrian Somers fprintf(stderr, "A system must be specified in auto mode.\n"); 271af57ed9fSAtsushi Murai exit(EX_START); 272af57ed9fSAtsushi Murai } 27339f94eddSBrian Somers 2747cf368ebSBrian Somers return arg; /* Don't SetLabel yet ! */ 275af57ed9fSAtsushi Murai } 276af57ed9fSAtsushi Murai 2777cf368ebSBrian Somers static void 2787cf368ebSBrian Somers CheckLabel(const char *label, struct prompt *prompt, int mode) 2797cf368ebSBrian Somers { 2807cf368ebSBrian Somers const char *err; 2817cf368ebSBrian Somers 2827cf368ebSBrian Somers if ((err = system_IsValid(label, prompt, mode)) != NULL) { 2837cf368ebSBrian Somers fprintf(stderr, "%s: %s\n", label, err); 2847cf368ebSBrian Somers if (mode == PHYS_DIRECT) 2857cf368ebSBrian Somers log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 2867cf368ebSBrian Somers label, err); 2877cf368ebSBrian Somers log_Close(); 2887cf368ebSBrian Somers exit(1); 2897cf368ebSBrian Somers } 2907cf368ebSBrian Somers } 2917cf368ebSBrian Somers 2927cf368ebSBrian Somers 2934ef16f24SBrian Somers int 294944f7098SBrian Somers main(int argc, char **argv) 295af57ed9fSAtsushi Murai { 2967cf368ebSBrian Somers char *name; 297756783fcSBrian Somers const char *lastlabel; 298108e336aSBrian Somers int arg, f, holdfd[3], label; 2997a6f8720SBrian Somers struct bundle *bundle; 300b6217683SBrian Somers struct prompt *prompt; 301c0593e34SBrian Somers struct switches sw; 302e3b4c400SBrian Somers 303108e336aSBrian Somers /* 304108e336aSBrian Somers * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 305108e336aSBrian Somers * STDERR_FILENO are always open. These are closed before DoLoop(), 306108e336aSBrian Somers * but *after* we've avoided the possibility of erroneously closing 307108e336aSBrian Somers * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 308108e336aSBrian Somers */ 309108e336aSBrian Somers if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 310108e336aSBrian Somers fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 311108e336aSBrian Somers return 2; 312108e336aSBrian Somers } 313108e336aSBrian Somers for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 314dd1a52b9SBrian Somers holdfd[f] = dup(holdfd[0]); 315108e336aSBrian Somers 31675240ed1SBrian Somers name = strrchr(argv[0], '/'); 317dd7e2610SBrian Somers log_Open(name ? name + 1 : argv[0]); 3182a279fedSBrian Somers 31967b072f7SBrian Somers #ifndef NONAT 3202a630835SBrian Somers PacketAliasInit(); 3212a630835SBrian Somers #endif 322c0593e34SBrian Somers label = ProcessArgs(argc, argv, &sw); 32385b542cfSBrian Somers 32485b542cfSBrian Somers /* 325a611383fSBrian Somers * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 326a611383fSBrian Somers * output occasionally.... I must find the real reason some time. To 327a611383fSBrian Somers * display the dodgy behaviour, comment out this bit, make yourself a large 32885b542cfSBrian Somers * routing table and then run ppp in interactive mode. The `show route' 32985b542cfSBrian Somers * command will drop chunks of data !!! 33085b542cfSBrian Somers */ 331c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) { 33285b542cfSBrian Somers close(STDIN_FILENO); 33385b542cfSBrian Somers if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 33485b542cfSBrian Somers fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 33585b542cfSBrian Somers return 2; 33685b542cfSBrian Somers } 33785b542cfSBrian Somers } 33885b542cfSBrian Somers 339b6217683SBrian Somers /* Allow output for the moment (except in direct mode) */ 340c0593e34SBrian Somers if (sw.mode == PHYS_DIRECT) 341b6217683SBrian Somers prompt = NULL; 342ed0e9269SBrian Somers else 343b6217683SBrian Somers SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 34412ef29a8SBrian Somers 3455106c671SBrian Somers ID0init(); 3464562be74SBrian Somers if (ID0realuid() != 0) { 3474562be74SBrian Somers char conf[200], *ptr; 3484562be74SBrian Somers 3497a66a36dSBrian Somers snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 3504562be74SBrian Somers do { 3511080ea25SBrian Somers struct stat sb; 3521080ea25SBrian Somers 3531080ea25SBrian Somers if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 354a33b2ef7SBrian Somers log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 355a33b2ef7SBrian Somers conf); 3564562be74SBrian Somers return -1; 3574562be74SBrian Somers } 3584562be74SBrian Somers ptr = conf + strlen(conf)-2; 3594562be74SBrian Somers while (ptr > conf && *ptr != '/') 3604562be74SBrian Somers *ptr-- = '\0'; 3614562be74SBrian Somers } while (ptr >= conf); 3624562be74SBrian Somers } 3634562be74SBrian Somers 3647cf368ebSBrian Somers if (label < argc) 3657cf368ebSBrian Somers for (arg = label; arg < argc; arg++) 366c0593e34SBrian Somers CheckLabel(argv[arg], prompt, sw.mode); 3677cf368ebSBrian Somers else 368c0593e34SBrian Somers CheckLabel("default", prompt, sw.mode); 36912ef29a8SBrian Somers 370c0593e34SBrian Somers if (!sw.quiet) 371c0593e34SBrian Somers prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 372ed0e9269SBrian Somers 373cf0a3940SBrian Somers if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 3744ef16f24SBrian Somers return EX_START; 375756783fcSBrian Somers 376756783fcSBrian Somers /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 377756783fcSBrian Somers 3780f2f3eb3SBrian Somers if (prompt) { 3790f2f3eb3SBrian Somers prompt->bundle = bundle; /* couldn't do it earlier */ 380c0593e34SBrian Somers if (!sw.quiet) 3818fa6ebe4SBrian Somers prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 3820f2f3eb3SBrian Somers } 38383d1af55SBrian Somers SignalBundle = bundle; 384c0593e34SBrian Somers bundle->NatEnabled = sw.nat; 385c0593e34SBrian Somers if (sw.nat) 3868fa6ebe4SBrian Somers bundle->cfg.opt |= OPT_IFACEALIAS; 38712ef29a8SBrian Somers 38830291ffbSBrian Somers if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 389565e35e5SBrian Somers prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 3901ae349f5Scvs2svn 391dd7e2610SBrian Somers sig_signal(SIGHUP, CloseSession); 392dd7e2610SBrian Somers sig_signal(SIGTERM, CloseSession); 393dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 394dd7e2610SBrian Somers sig_signal(SIGQUIT, CloseSession); 395dd7e2610SBrian Somers sig_signal(SIGALRM, SIG_IGN); 396e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 397565e35e5SBrian Somers 398c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) 399dd7e2610SBrian Somers sig_signal(SIGTSTP, TerminalStop); 400f91ad6b0SBrian Somers 40174457d3dSBrian Somers sig_signal(SIGUSR1, RestartServer); 402dd7e2610SBrian Somers sig_signal(SIGUSR2, BringDownServer); 403af57ed9fSAtsushi Murai 404cf0a3940SBrian Somers lastlabel = argv[argc - 1]; 4057cf368ebSBrian Somers for (arg = label; arg < argc; arg++) { 4067cf368ebSBrian Somers /* In case we use LABEL or ``set enddisc label'' */ 407756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 408cf0a3940SBrian Somers system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 4091ae349f5Scvs2svn } 4107cf368ebSBrian Somers 4117cf368ebSBrian Somers if (label < argc) 4127cf368ebSBrian Somers /* In case the last label did a ``load'' */ 413756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 4147cf368ebSBrian Somers 415c0593e34SBrian Somers if (sw.mode == PHYS_AUTO && 4165828db6dSBrian Somers bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 4177cf368ebSBrian Somers prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 4187cf368ebSBrian Somers "in auto mode.\n"); 4198390b576SBrian Somers AbortProgram(EX_START); 420af57ed9fSAtsushi Murai } 4216efd9292SBrian Somers 422c0593e34SBrian Somers if (sw.mode != PHYS_INTERACTIVE) { 423c0593e34SBrian Somers if (sw.mode != PHYS_DIRECT) { 424c0593e34SBrian Somers if (!sw.fg) { 4255cf4388bSBrian Somers int bgpipe[2]; 4266d14e2a8SJordan K. Hubbard pid_t bgpid; 427a9c6b5dfSAtsushi Murai 428c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 429dd7e2610SBrian Somers log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 4308390b576SBrian Somers AbortProgram(EX_SOCK); 4311ae349f5Scvs2svn } 4321ae349f5Scvs2svn 4336d14e2a8SJordan K. Hubbard bgpid = fork(); 4346d14e2a8SJordan K. Hubbard if (bgpid == -1) { 435dd7e2610SBrian Somers log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 4368390b576SBrian Somers AbortProgram(EX_SOCK); 4376d14e2a8SJordan K. Hubbard } 4385cf4388bSBrian Somers 4396d14e2a8SJordan K. Hubbard if (bgpid) { 4406d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 441b42135deSBrian Somers int ret; 442a9c6b5dfSAtsushi Murai 443c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND) { 4445cf4388bSBrian Somers close(bgpipe[1]); 4456d14e2a8SJordan K. Hubbard BGPid = bgpid; 44675b8d283SBrian Somers /* If we get a signal, kill the child */ 44775b8d283SBrian Somers signal(SIGHUP, KillChild); 44875b8d283SBrian Somers signal(SIGTERM, KillChild); 44975b8d283SBrian Somers signal(SIGINT, KillChild); 45075b8d283SBrian Somers signal(SIGQUIT, KillChild); 45175b8d283SBrian Somers 45275b8d283SBrian Somers /* Wait for our child to close its pipe before we exit */ 453b42135deSBrian Somers while ((ret = read(bgpipe[0], &c, 1)) == 1) { 454b42135deSBrian Somers switch (c) { 455b42135deSBrian Somers case EX_NORMAL: 4560fea4ed0SBrian Somers if (!sw.quiet) { 457b42135deSBrian Somers prompt_Printf(prompt, "PPP enabled\n"); 458b42135deSBrian Somers log_Printf(LogPHASE, "Parent: PPP enabled\n"); 4590fea4ed0SBrian Somers } 4609bf01bcbSBrian Somers break; 461b42135deSBrian Somers case EX_REDIAL: 462b42135deSBrian Somers if (!sw.quiet) 463b42135deSBrian Somers prompt_Printf(prompt, "Attempting redial\n"); 464b42135deSBrian Somers continue; 465b42135deSBrian Somers case EX_RECONNECT: 466b42135deSBrian Somers if (!sw.quiet) 467b42135deSBrian Somers prompt_Printf(prompt, "Attempting reconnect\n"); 468b42135deSBrian Somers continue; 469b42135deSBrian Somers default: 470b42135deSBrian Somers prompt_Printf(prompt, "Child failed (%s)\n", 471b42135deSBrian Somers ex_desc((int)c)); 472b42135deSBrian Somers log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 473b42135deSBrian Somers ex_desc((int) c)); 474b42135deSBrian Somers } 475b42135deSBrian Somers break; 476b42135deSBrian Somers } 477b42135deSBrian Somers if (ret != 1) { 478b6217683SBrian Somers prompt_Printf(prompt, "Child exit, no status.\n"); 479dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 4806efd9292SBrian Somers } 4815cf4388bSBrian Somers close(bgpipe[0]); 4826d14e2a8SJordan K. Hubbard } 4834ef16f24SBrian Somers return c; 484c0593e34SBrian Somers } else if (sw.mode == PHYS_BACKGROUND) { 4855cf4388bSBrian Somers close(bgpipe[0]); 4865cf4388bSBrian Somers bundle->notify.fd = bgpipe[1]; 487aefd026aSBrian Somers } 488aefd026aSBrian Somers 48906b47306SBrian Somers bundle_ChangedPID(bundle); 490da66dd13SBrian Somers bundle_LockTun(bundle); /* we have a new pid */ 49167b072f7SBrian Somers } 492da66dd13SBrian Somers 49367b072f7SBrian Somers /* -auto, -dedicated, -ddial, -foreground & -background */ 494b6217683SBrian Somers prompt_Destroy(prompt, 0); 4952a279fedSBrian Somers close(STDOUT_FILENO); 4962a279fedSBrian Somers close(STDERR_FILENO); 4972a279fedSBrian Somers close(STDIN_FILENO); 498c0593e34SBrian Somers if (!sw.fg) 499b6217683SBrian Somers setsid(); 500565e35e5SBrian Somers } else { 50167b072f7SBrian Somers /* -direct - STDIN_FILENO gets used by physical_Open */ 502565e35e5SBrian Somers prompt_TtyInit(NULL); 503565e35e5SBrian Somers close(STDOUT_FILENO); 504565e35e5SBrian Somers close(STDERR_FILENO); 505d656a4c5SBrian Somers } 506af57ed9fSAtsushi Murai } else { 50767b072f7SBrian Somers /* -interactive */ 5082a279fedSBrian Somers close(STDERR_FILENO); 509565e35e5SBrian Somers prompt_TtyInit(prompt); 510b6217683SBrian Somers prompt_TtyCommandMode(prompt); 511b6217683SBrian Somers prompt_Required(prompt); 512af57ed9fSAtsushi Murai } 51335495becSBrian Somers 514108e336aSBrian Somers /* We can get rid of these now */ 515108e336aSBrian Somers for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 516108e336aSBrian Somers close(holdfd[f]); 517108e336aSBrian Somers 518c0593e34SBrian Somers log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 5190f78c7a7SBrian Somers DoLoop(bundle); 5201afedc4bSBrian Somers AbortProgram(EX_NORMAL); 521af57ed9fSAtsushi Murai 5221afedc4bSBrian Somers return EX_NORMAL; 523af57ed9fSAtsushi Murai } 524af57ed9fSAtsushi Murai 525af57ed9fSAtsushi Murai static void 5260f78c7a7SBrian Somers DoLoop(struct bundle *bundle) 527af57ed9fSAtsushi Murai { 5288a52f3ecSBrian Somers fd_set *rfds, *wfds, *efds; 5291af29a6eSBrian Somers int i, nfds, nothing_done; 5301af29a6eSBrian Somers struct probe probe; 5311af29a6eSBrian Somers 5321af29a6eSBrian Somers probe_Init(&probe); 533c3899f8dSAtsushi Murai 5348a52f3ecSBrian Somers if ((rfds = mkfdset()) == NULL) { 5358a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5368a52f3ecSBrian Somers return; 5378a52f3ecSBrian Somers } 5388a52f3ecSBrian Somers 5398a52f3ecSBrian Somers if ((wfds = mkfdset()) == NULL) { 5408a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5418a52f3ecSBrian Somers free(rfds); 5428a52f3ecSBrian Somers return; 5438a52f3ecSBrian Somers } 5448a52f3ecSBrian Somers 5458a52f3ecSBrian Somers if ((efds = mkfdset()) == NULL) { 5468a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5478a52f3ecSBrian Somers free(rfds); 5488a52f3ecSBrian Somers free(wfds); 5498a52f3ecSBrian Somers return; 5508a52f3ecSBrian Somers } 5518a52f3ecSBrian Somers 552da8b7034SBrian Somers for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 553780700e5SAndrey A. Chernov nfds = 0; 5548a52f3ecSBrian Somers zerofdset(rfds); 5558a52f3ecSBrian Somers zerofdset(wfds); 5568a52f3ecSBrian Somers zerofdset(efds); 55784b8a6ebSAtsushi Murai 5580f2f3eb3SBrian Somers /* All our datalinks, the tun device and the MP socket */ 5598a52f3ecSBrian Somers descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 5600f2f3eb3SBrian Somers 5610f2f3eb3SBrian Somers /* All our prompts and the diagnostic socket */ 5628a52f3ecSBrian Somers descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 56307030d97SBrian Somers 5640cd8e902SBrian Somers bundle_CleanDatalinks(bundle); 5653b0f8d2eSBrian Somers if (bundle_IsDead(bundle)) 566f4768038SBrian Somers /* Don't select - we'll be here forever */ 567f4768038SBrian Somers break; 5680706ff38SBrian Somers 569486105bcSBrian Somers /* 570486105bcSBrian Somers * It's possible that we've had a signal since we last checked. If 571486105bcSBrian Somers * we don't check again before calling select(), we may end up stuck 572486105bcSBrian Somers * after having missed the event.... sig_Handle() tries to be as 573486105bcSBrian Somers * quick as possible if nothing is likely to have happened. 574486105bcSBrian Somers * This is only really likely if we block in open(... O_NONBLOCK) 575486105bcSBrian Somers * which will happen with a misconfigured device. 576486105bcSBrian Somers */ 577486105bcSBrian Somers if (sig_Handle()) 578486105bcSBrian Somers continue; 579486105bcSBrian Somers 5808a52f3ecSBrian Somers i = select(nfds, rfds, wfds, efds, NULL); 581712ae387SBrian Somers 58254cd8e13SBrian Somers if (i < 0 && errno != EINTR) { 583dd7e2610SBrian Somers log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 58424989c68SBrian Somers if (log_IsKept(LogTIMER)) { 58524989c68SBrian Somers struct timeval t; 58624989c68SBrian Somers 58724989c68SBrian Somers for (i = 0; i <= nfds; i++) { 5888a52f3ecSBrian Somers if (FD_ISSET(i, rfds)) { 58924989c68SBrian Somers log_Printf(LogTIMER, "Read set contains %d\n", i); 5908a52f3ecSBrian Somers FD_CLR(i, rfds); 59124989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 5928a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 59324989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 594af57ed9fSAtsushi Murai break; 595af57ed9fSAtsushi Murai } 59624989c68SBrian Somers } 5978a52f3ecSBrian Somers if (FD_ISSET(i, wfds)) { 59824989c68SBrian Somers log_Printf(LogTIMER, "Write set contains %d\n", i); 5998a52f3ecSBrian Somers FD_CLR(i, wfds); 60024989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 6018a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 60224989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 603af57ed9fSAtsushi Murai break; 604af57ed9fSAtsushi Murai } 605e0d3e233SAndrey A. Chernov } 6068a52f3ecSBrian Somers if (FD_ISSET(i, efds)) { 60724989c68SBrian Somers log_Printf(LogTIMER, "Error set contains %d\n", i); 6088a52f3ecSBrian Somers FD_CLR(i, efds); 60924989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 6108a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 61124989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 61258f264e1SBrian Somers break; 61358f264e1SBrian Somers } 61424989c68SBrian Somers } 61524989c68SBrian Somers } 61624989c68SBrian Somers } 61758f264e1SBrian Somers break; 618de451c68SBrian Somers } 619de451c68SBrian Somers 620f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Select returns %d\n", i); 621f0cdd9c0SBrian Somers 62254cd8e13SBrian Somers sig_Handle(); 62354cd8e13SBrian Somers 62454cd8e13SBrian Somers if (i <= 0) 62554cd8e13SBrian Somers continue; 62654cd8e13SBrian Somers 6273006ec67SBrian Somers for (i = 0; i <= nfds; i++) 6288a52f3ecSBrian Somers if (FD_ISSET(i, efds)) { 6298e7bd08eSBrian Somers log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 6308e7bd08eSBrian Somers /* We deal gracefully with link descriptor exceptions */ 631991c2a7bSBrian Somers if (!bundle_Exception(bundle, i)) { 632991c2a7bSBrian Somers log_Printf(LogERROR, "Exception cannot be handled !\n"); 6331ae349f5Scvs2svn break; 6341ae349f5Scvs2svn } 635991c2a7bSBrian Somers } 636c60f92caSBrian Somers 637b7c5748eSBrian Somers if (i <= nfds) 638b7c5748eSBrian Somers break; 639b7c5748eSBrian Somers 6401af29a6eSBrian Somers nothing_done = 1; 6411af29a6eSBrian Somers 6428a52f3ecSBrian Somers if (descriptor_IsSet(&server.desc, rfds)) { 6438a52f3ecSBrian Somers descriptor_Read(&server.desc, bundle, rfds); 6441af29a6eSBrian Somers nothing_done = 0; 6451af29a6eSBrian Somers } 6461af29a6eSBrian Somers 6478a52f3ecSBrian Somers if (descriptor_IsSet(&bundle->desc, rfds)) { 6488a52f3ecSBrian Somers descriptor_Read(&bundle->desc, bundle, rfds); 6491af29a6eSBrian Somers nothing_done = 0; 6501af29a6eSBrian Somers } 65142d4d396SBrian Somers 6528a52f3ecSBrian Somers if (descriptor_IsSet(&bundle->desc, wfds)) 6538a52f3ecSBrian Somers if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) { 6541af29a6eSBrian Somers /* 6551af29a6eSBrian Somers * This is disasterous. The OS has told us that something is 6561af29a6eSBrian Somers * writable, and all our write()s have failed. Rather than 6571af29a6eSBrian Somers * going back immediately to do our UpdateSet()s and select(), 6581af29a6eSBrian Somers * we sleep for a bit to avoid gobbling up all cpu time. 6591af29a6eSBrian Somers */ 6601af29a6eSBrian Somers struct timeval t; 6612f786681SBrian Somers 6621af29a6eSBrian Somers t.tv_sec = 0; 6631af29a6eSBrian Somers t.tv_usec = 100000; 6641af29a6eSBrian Somers select(0, NULL, NULL, NULL, &t); 6651af29a6eSBrian Somers } 666da8b7034SBrian Somers } 667565e35e5SBrian Somers 668dd7e2610SBrian Somers log_Printf(LogDEBUG, "DoLoop done.\n"); 669af57ed9fSAtsushi Murai } 670