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