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