Mercurial > illumos > onarm
comparison usr/src/cmd/cmd-inet/usr.bin/pppd/main.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
1 /* | |
2 * main.c - Point-to-Point Protocol main module | |
3 * | |
4 * Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved. | |
5 * Use is subject to license terms. | |
6 * | |
7 * Permission to use, copy, modify, and distribute this software and its | |
8 * documentation is hereby granted, provided that the above copyright | |
9 * notice appears in all copies. | |
10 * | |
11 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF | |
12 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |
13 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |
14 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR | |
15 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
16 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES | |
17 * | |
18 * Copyright (c) 1989 Carnegie Mellon University. | |
19 * All rights reserved. | |
20 * | |
21 * Redistribution and use in source and binary forms are permitted | |
22 * provided that the above copyright notice and this paragraph are | |
23 * duplicated in all such forms and that any documentation, | |
24 * advertising materials, and other materials related to such | |
25 * distribution and use acknowledge that the software was developed | |
26 * by Carnegie Mellon University. The name of the | |
27 * University may not be used to endorse or promote products derived | |
28 * from this software without specific prior written permission. | |
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
32 */ | |
33 | |
34 #pragma ident "@(#)main.c 1.8 02/06/20 SMI" | |
35 #define RCSID "$Id: main.c,v 1.97 2000/04/24 02:54:16 masputra Exp $" | |
36 | |
37 #include <stdio.h> | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
40 #include <unistd.h> | |
41 #include <signal.h> | |
42 #include <errno.h> | |
43 #include <fcntl.h> | |
44 #include <syslog.h> | |
45 #include <netdb.h> | |
46 #include <pwd.h> | |
47 #include <setjmp.h> | |
48 #include <sys/param.h> | |
49 #include <sys/types.h> | |
50 #include <sys/wait.h> | |
51 #include <sys/time.h> | |
52 #include <sys/resource.h> | |
53 #include <sys/stat.h> | |
54 #include <sys/socket.h> | |
55 #include <netinet/in.h> | |
56 #include <arpa/inet.h> | |
57 | |
58 #include "pppd.h" | |
59 #include "magic.h" | |
60 #include "fsm.h" | |
61 #include "lcp.h" | |
62 #include "ipcp.h" | |
63 #ifdef INET6 | |
64 #include "ipv6cp.h" | |
65 #endif | |
66 #include "upap.h" | |
67 #include "chap.h" | |
68 #include "ccp.h" | |
69 #include "pathnames.h" | |
70 #include "patchlevel.h" | |
71 | |
72 #ifdef HAVE_MULTILINK | |
73 #include "tdb.h" | |
74 #endif | |
75 | |
76 #ifdef CBCP_SUPPORT | |
77 #include "cbcp.h" | |
78 #endif | |
79 | |
80 #ifdef IPX_CHANGE | |
81 #include "ipxcp.h" | |
82 #endif /* IPX_CHANGE */ | |
83 #ifdef AT_CHANGE | |
84 #include "atcp.h" | |
85 #endif | |
86 | |
87 #if !defined(lint) && !defined(_lint) | |
88 static const char rcsid[] = RCSID; | |
89 #endif | |
90 | |
91 /* interface vars */ | |
92 char ifname[32]; /* Interface name */ | |
93 int ifunit = -1; /* Interface unit number */ | |
94 | |
95 char *progname; /* Name of this program */ | |
96 char hostname[MAXHOSTNAMELEN+1]; /* Our hostname */ | |
97 static char pidfilename[MAXPATHLEN]; /* name of pid file */ | |
98 static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */ | |
99 char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */ | |
100 static uid_t uid; /* Our real user-id */ | |
101 static int conn_running; /* we have a [dis]connector running */ | |
102 | |
103 int ttyfd; /* Serial port file descriptor */ | |
104 mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */ | |
105 int baud_rate; /* Actual bits/second for serial device */ | |
106 bool hungup; /* terminal has been hung up */ | |
107 bool privileged; /* we're running as real uid root */ | |
108 bool need_holdoff; /* need holdoff period before restarting */ | |
109 bool detached; /* have detached from terminal */ | |
110 struct stat devstat; /* result of stat() on devnam */ | |
111 bool prepass = 0; /* doing prepass to find device name */ | |
112 int devnam_fixed; /* set while in options.ttyxx file */ | |
113 volatile int status; /* exit status for pppd */ | |
114 int unsuccess; /* # unsuccessful connection attempts */ | |
115 int do_callback; /* != 0 if we should do callback next */ | |
116 int doing_callback; /* != 0 if we are doing callback */ | |
117 char *callback_script; /* script for doing callback */ | |
118 #ifdef HAVE_MULTILINK | |
119 TDB_CONTEXT *pppdb; /* database for storing status etc. */ | |
120 char db_key[32]; | |
121 #endif | |
122 | |
123 /* | |
124 * For plug-in usage: | |
125 * | |
126 * holdoff_hook - Can be used to change the demand-dial hold-off | |
127 * time dynamically. This is normally set by the | |
128 * "holdoff" option, and is 30 seconds by default. | |
129 * | |
130 * new_phase_hook - This is called for each change in the PPP | |
131 * phase (per RFC 1661). This can be used to log | |
132 * progress. | |
133 * | |
134 * check_options_hook - This is called before doing sys_init() | |
135 * and allows the plugin to verify the selected options. | |
136 * | |
137 * updown_script_hook - This is called with the proposed | |
138 * command-line arguments for any of the | |
139 * /etc/ppp/{ip,ipv6,ipx,auth}-{up,down} scripts before | |
140 * fork/exec. It can be used to add or change arguments. | |
141 * | |
142 * device_pipe_hook - If this is set, then an extra fd (3) is | |
143 * passed to the connect/disconnect script. This extra | |
144 * fd is the write side of a pipe, and the read side is | |
145 * passed to this routine. This can be used to pass | |
146 * arbitrary data from the script back to pppd. | |
147 */ | |
148 int (*holdoff_hook) __P((void)) = NULL; | |
149 int (*new_phase_hook) __P((int new, int old)) = NULL; | |
150 int (*check_options_hook) __P((uid_t uid)) = NULL; | |
151 int (*updown_script_hook) __P((const char ***argsp)) = NULL; | |
152 void (*device_pipe_hook) __P((int pipefd)) = NULL; | |
153 | |
154 static int fd_ppp = -1; /* fd for talking PPP */ | |
155 static int fd_loop; /* fd for getting demand-dial packets */ | |
156 static int pty_master; /* fd for master side of pty */ | |
157 int pty_slave = -1; /* fd for slave side of pty */ | |
158 static int real_ttyfd; /* fd for actual serial port (not pty) */ | |
159 | |
160 int phase; /* where the link is at */ | |
161 int kill_link; | |
162 int open_ccp_flag; | |
163 | |
164 static int waiting; /* for input from peer or timer expiration */ | |
165 static sigjmp_buf sigjmp; | |
166 | |
167 char **script_env; /* Env. variable values for scripts */ | |
168 int s_env_nalloc; /* # words avail at script_env */ | |
169 | |
170 u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */ | |
171 u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */ | |
172 u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ | |
173 | |
174 static int n_children; /* # child processes still running */ | |
175 static bool got_sigchld; /* set if we have received a SIGCHLD */ | |
176 static sigset_t main_sigmask; /* signals blocked while dispatching */ | |
177 | |
178 static bool locked; /* lock() has succeeded */ | |
179 static bool privopen; /* don't lock, open device as root */ | |
180 | |
181 char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n"; | |
182 | |
183 GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */ | |
184 int ngroups; /* How many groups valid in groups */ | |
185 | |
186 static struct timeval start_time; /* Time when link was started. */ | |
187 | |
188 struct pppd_stats link_stats; | |
189 int link_connect_time; | |
190 bool link_stats_valid; | |
191 | |
192 static pid_t charshunt_pid; /* Process ID for charshunt */ | |
193 | |
194 extern option_t general_options[]; | |
195 extern option_t auth_options[]; | |
196 | |
197 /* | |
198 * We maintain a list of child process pids and | |
199 * functions to call when they exit. | |
200 */ | |
201 struct subprocess { | |
202 pid_t pid; | |
203 char *prog; | |
204 void (*done) __P((void *, int)); | |
205 void *arg; | |
206 struct subprocess *next; | |
207 }; | |
208 | |
209 static struct subprocess *children; | |
210 | |
211 /* Prototypes for procedures local to this file. */ | |
212 | |
213 static void setup_signals __P((void)); | |
214 static void create_pidfile __P((void)); | |
215 static void create_linkpidfile __P((void)); | |
216 static void cleanup __P((void)); | |
217 static void close_tty __P((void)); | |
218 static void get_input __P((void)); | |
219 static void calltimeout __P((void)); | |
220 static struct timeval *timeleft __P((struct timeval *)); | |
221 static void kill_my_pg __P((int)); | |
222 static void hup __P((int)); | |
223 static void term __P((int)); | |
224 static void chld __P((int)); | |
225 static void toggle_debug __P((int)); | |
226 static void open_ccp __P((int)); | |
227 static void bad_signal __P((int)); | |
228 static void holdoff_end __P((void *)); | |
229 static int device_script __P((char *, int, int, int, char *)); | |
230 static int reap_kids __P((int waitfor)); | |
231 static void record_child __P((pid_t, char *, void (*) (void *, int), void *)); | |
232 static int open_socket __P((char *)); | |
233 static int start_charshunt __P((int, int)); | |
234 static void charshunt_done __P((void *, int)); | |
235 static void charshunt __P((int, int, char *)); | |
236 static int record_write __P((FILE *, int code, u_char *buf, int nb, | |
237 struct timeval *)); | |
238 static void final_reap __P((void)); | |
239 | |
240 #ifdef HAVE_MULTILINK | |
241 static void update_db_entry __P((void)); | |
242 static void add_db_key __P((const char *)); | |
243 static void delete_db_key __P((const char *)); | |
244 static void cleanup_db __P((void)); | |
245 #endif | |
246 | |
247 int main __P((int, char *[])); | |
248 | |
249 #ifdef ultrix | |
250 #undef O_NONBLOCK | |
251 #define O_NONBLOCK O_NDELAY | |
252 #endif | |
253 | |
254 #ifdef ULTRIX | |
255 #define setlogmask(x) 0 | |
256 #endif | |
257 | |
258 /* Backward compatibility for Linux */ | |
259 #ifndef RECMARK_TIMESTART | |
260 #define RECMARK_STARTSEND 1 | |
261 #define RECMARK_STARTRECV 2 | |
262 #define RECMARK_ENDSEND 3 | |
263 #define RECMARK_ENDRECV 4 | |
264 #define RECMARK_TIMEDELTA32 5 | |
265 #define RECMARK_TIMEDELTA8 6 | |
266 #define RECMARK_TIMESTART 7 | |
267 #endif | |
268 | |
269 /* | |
270 * PPP Data Link Layer "protocol" table. | |
271 * One entry per supported protocol. | |
272 * The last entry must be NULL. | |
273 */ | |
274 struct protent *protocols[] = { | |
275 &lcp_protent, | |
276 &pap_protent, | |
277 &chap_protent, | |
278 #ifdef CBCP_SUPPORT | |
279 &cbcp_protent, | |
280 #endif | |
281 &ipcp_protent, | |
282 #ifdef INET6 | |
283 &ipv6cp_protent, | |
284 #endif | |
285 &ccp_protent, | |
286 #ifdef IPX_CHANGE | |
287 &ipxcp_protent, | |
288 #endif | |
289 #ifdef AT_CHANGE | |
290 &atcp_protent, | |
291 #endif | |
292 NULL | |
293 }; | |
294 | |
295 int | |
296 main(argc, argv) | |
297 int argc; | |
298 char *argv[]; | |
299 { | |
300 int i, fdflags, t; | |
301 char *p, *connector; | |
302 struct passwd *pw; | |
303 struct timeval timo; | |
304 struct protent *protp; | |
305 struct stat statbuf; | |
306 char numbuf[16]; | |
307 | |
308 ifname[0] = '\0'; | |
309 new_phase(PHASE_INITIALIZE); | |
310 | |
311 /* | |
312 * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else. | |
313 * This way we can close 0, 1, 2 in detach() without clobbering | |
314 * a fd that we are using. | |
315 */ | |
316 if ((i = open(_PATH_DEVNULL, O_RDWR)) >= 0) { | |
317 while (0 <= i && i <= 2) | |
318 i = dup(i); | |
319 if (i >= 0) | |
320 (void) close(i); | |
321 } | |
322 | |
323 script_env = NULL; | |
324 | |
325 /* Initialize syslog facilities */ | |
326 reopen_log(); | |
327 | |
328 if (gethostname(hostname, MAXHOSTNAMELEN+1) < 0 ) { | |
329 option_error("Couldn't get hostname: %m"); | |
330 exit(1); | |
331 } | |
332 hostname[MAXHOSTNAMELEN] = '\0'; | |
333 | |
334 /* make sure we don't create world or group writable files. */ | |
335 (void) umask(umask(0777) | 022); | |
336 | |
337 uid = getuid(); | |
338 privileged = (uid == 0); | |
339 (void) slprintf(numbuf, sizeof(numbuf), "%d", uid); | |
340 script_setenv("ORIG_UID", numbuf, 0); | |
341 | |
342 ngroups = getgroups(NGROUPS_MAX, groups); | |
343 | |
344 /* | |
345 * Initialize magic number generator now so that protocols may | |
346 * use magic numbers in initialization. | |
347 */ | |
348 magic_init(); | |
349 | |
350 progname = *argv; | |
351 prepass = 0; | |
352 /* | |
353 * Initialize to the standard option set, then parse, in order, the | |
354 * system options file, the user's options file, the tty's options file, | |
355 * and the command line arguments. At last, install the options declared | |
356 * by each protocol into the extra_option list. | |
357 */ | |
358 for (i = 0; (protp = protocols[i]) != NULL; ++i) { | |
359 (*protp->init)(0); | |
360 if (protp->options != NULL) { | |
361 add_options(protp->options); | |
362 } | |
363 } | |
364 | |
365 /* | |
366 * Install "generic" options into the extra_options list. | |
367 */ | |
368 add_options(auth_options); | |
369 add_options(general_options); | |
370 | |
371 /* Install any system-specific options (or remove unusable ones) */ | |
372 sys_options(); | |
373 | |
374 if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1) | |
375 || !options_from_user()) | |
376 exit(EXIT_OPTION_ERROR); | |
377 | |
378 /* scan command line and options files to find device name */ | |
379 prepass = 1; | |
380 (void) parse_args(argc-1, argv+1); | |
381 prepass = 0; | |
382 | |
383 /* | |
384 * Work out the device name, if it hasn't already been specified. | |
385 */ | |
386 using_pty = notty || ptycommand != NULL || pty_socket != NULL; | |
387 if (!using_pty && default_device && !direct_tty) { | |
388 char *p; | |
389 | |
390 if (!isatty(0) || (p = ttyname(0)) == NULL) { | |
391 option_error("no device specified and stdin is not a tty"); | |
392 exit(EXIT_OPTION_ERROR); | |
393 } | |
394 (void) strlcpy(devnam, p, sizeof(devnam)); | |
395 if (stat(devnam, &devstat) < 0) | |
396 fatal("Couldn't stat default device %s: %m", devnam); | |
397 } | |
398 | |
399 /* | |
400 * Parse the tty options file and the command line. | |
401 * The per-tty options file should not change | |
402 * ptycommand, pty_socket, notty or devnam. | |
403 */ | |
404 devnam_fixed = 1; | |
405 if (!using_pty && !direct_tty) { | |
406 if (!options_for_tty()) | |
407 exit(EXIT_OPTION_ERROR); | |
408 } | |
409 | |
410 devnam_fixed = 0; | |
411 if (!parse_args(argc-1, argv+1)) | |
412 exit(EXIT_OPTION_ERROR); | |
413 | |
414 /* | |
415 * Check that we are running as root. | |
416 */ | |
417 if (geteuid() != 0) { | |
418 option_error("must be root to run %s, since it is not setuid-root", | |
419 argv[0]); | |
420 exit(EXIT_NOT_ROOT); | |
421 } | |
422 | |
423 if (!ppp_available()) { | |
424 option_error(no_ppp_msg); | |
425 exit(EXIT_NO_KERNEL_SUPPORT); | |
426 } | |
427 | |
428 /* | |
429 * Check that the options given are valid and consistent. | |
430 */ | |
431 if (!sys_check_options()) | |
432 exit(EXIT_OPTION_ERROR); | |
433 auth_check_options(); | |
434 #ifdef HAVE_MULTILINK | |
435 mp_check_options(); | |
436 #endif | |
437 for (i = 0; (protp = protocols[i]) != NULL; ++i) | |
438 if (protp->enabled_flag && protp->check_options != NULL) | |
439 (*protp->check_options)(); | |
440 if (demand && (connect_script == NULL)) { | |
441 option_error("connect script is required for demand-dialling\n"); | |
442 exit(EXIT_OPTION_ERROR); | |
443 } | |
444 if (updetach && (nodetach || demand)) { | |
445 option_error("updetach cannot be used with %s", | |
446 nodetach ? "nodetach" : "demand"); | |
447 exit(EXIT_OPTION_ERROR); | |
448 } | |
449 /* default holdoff to 0 if no connect script has been given */ | |
450 if ((connect_script == NULL) && !holdoff_specified) | |
451 holdoff = 0; | |
452 | |
453 if (using_pty || direct_tty) { | |
454 if (!default_device) { | |
455 option_error("%s option precludes specifying device name", | |
456 notty? "notty": "pty"); | |
457 exit(EXIT_OPTION_ERROR); | |
458 } | |
459 if (ptycommand != NULL && (notty || direct_tty)) { | |
460 option_error("pty option is incompatible with notty option"); | |
461 exit(EXIT_OPTION_ERROR); | |
462 } | |
463 if (pty_socket != NULL && (ptycommand != NULL || notty || | |
464 direct_tty)) { | |
465 option_error("socket option is incompatible with pty and notty"); | |
466 exit(EXIT_OPTION_ERROR); | |
467 } | |
468 default_device = notty || direct_tty; | |
469 lockflag = 0; | |
470 modem = 0; | |
471 if (default_device && log_to_fd <= 1) | |
472 log_to_fd = -1; | |
473 } else { | |
474 /* | |
475 * If the user has specified a device which is the same as | |
476 * the one on stdin, pretend they didn't specify any. | |
477 * If the device is already open read/write on stdin, | |
478 * we assume we don't need to lock it, and we can open it as root. | |
479 */ | |
480 if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode) | |
481 && statbuf.st_rdev == devstat.st_rdev) { | |
482 default_device = 1; | |
483 fdflags = fcntl(0, F_GETFL); | |
484 if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR) | |
485 privopen = 1; | |
486 } | |
487 } | |
488 if (default_device) | |
489 nodetach = 1; | |
490 | |
491 /* | |
492 * Don't send log messages to the serial port, it tends to | |
493 * confuse the peer. :-) | |
494 */ | |
495 if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0 | |
496 && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev) | |
497 log_to_fd = -1; | |
498 early_log = 0; | |
499 | |
500 if (debug) | |
501 (void) setlogmask(LOG_UPTO(LOG_DEBUG)); | |
502 | |
503 /* | |
504 * Initialize system-dependent stuff. | |
505 */ | |
506 if (check_options_hook != NULL && | |
507 (*check_options_hook)(uid) == -1) { | |
508 exit(EXIT_OPTION_ERROR); | |
509 } | |
510 sys_init(!devnam_info.priv && !privopen); | |
511 | |
512 #ifdef HAVE_MULTILINK | |
513 pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644); | |
514 if (pppdb != NULL) { | |
515 (void) slprintf(db_key, sizeof(db_key), "pppd%d", getpid()); | |
516 update_db_entry(); | |
517 } else { | |
518 warn("Warning: couldn't open ppp database %s", _PATH_PPPDB); | |
519 if (multilink) { | |
520 warn("Warning: disabling multilink"); | |
521 multilink = 0; | |
522 } | |
523 } | |
524 #endif | |
525 | |
526 /* | |
527 * Detach ourselves from the terminal, if required, and identify | |
528 * who is running us. Printing to stderr stops here unless | |
529 * nodetach or updetach is set. | |
530 */ | |
531 if (!nodetach && !updetach) | |
532 detach(); | |
533 p = getlogin(); | |
534 if (p == NULL) { | |
535 pw = getpwuid(uid); | |
536 if (pw != NULL && pw->pw_name != NULL) | |
537 p = pw->pw_name; | |
538 else | |
539 p = "(unknown)"; | |
540 } | |
541 syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d", | |
542 VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid); | |
543 script_setenv("PPPLOGNAME", p, 0); | |
544 | |
545 if (devnam[0] != '\0') | |
546 script_setenv("DEVICE", devnam, 1); | |
547 (void) slprintf(numbuf, sizeof(numbuf), "%d", getpid()); | |
548 script_setenv("PPPD_PID", numbuf, 1); | |
549 | |
550 setup_signals(); | |
551 | |
552 waiting = 0; | |
553 | |
554 create_linkpidfile(); | |
555 | |
556 /* | |
557 * If we're doing dial-on-demand, set up the interface now. | |
558 */ | |
559 if (demand) { | |
560 /* | |
561 * Open the loopback channel and set it up to be the ppp interface. | |
562 */ | |
563 #ifdef HAVE_MULTILINK | |
564 (void) tdb_writelock(pppdb); | |
565 #endif | |
566 set_ifunit(1); | |
567 fd_loop = open_ppp_loopback(); | |
568 #ifdef HAVE_MULTILINK | |
569 (void) tdb_writeunlock(pppdb); | |
570 #endif | |
571 | |
572 /* | |
573 * Configure the interface and mark it up, etc. | |
574 */ | |
575 demand_conf(); | |
576 } | |
577 | |
578 new_phase(PHASE_INITIALIZED); | |
579 do_callback = 0; | |
580 for (;;) { | |
581 | |
582 need_holdoff = 1; | |
583 ttyfd = -1; | |
584 real_ttyfd = -1; | |
585 status = EXIT_OK; | |
586 ++unsuccess; | |
587 doing_callback = do_callback; | |
588 do_callback = 0; | |
589 | |
590 if (demand && !doing_callback) { | |
591 /* | |
592 * Don't do anything until we see some activity. | |
593 */ | |
594 kill_link = 0; | |
595 new_phase(PHASE_DORMANT); | |
596 demand_unblock(); | |
597 add_fd(fd_loop); | |
598 for (;;) { | |
599 if (sigsetjmp(sigjmp, 1) == 0) { | |
600 (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); | |
601 if (kill_link || got_sigchld) { | |
602 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
603 } else { | |
604 waiting = 1; | |
605 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
606 wait_input(timeleft(&timo)); | |
607 } | |
608 } | |
609 waiting = 0; | |
610 calltimeout(); | |
611 if (kill_link) { | |
612 if (!persist) | |
613 break; | |
614 kill_link = 0; | |
615 } | |
616 if (get_loop_output()) | |
617 break; | |
618 if (got_sigchld) | |
619 (void) reap_kids(0); | |
620 } | |
621 remove_fd(fd_loop); | |
622 if (kill_link && !persist) | |
623 break; | |
624 | |
625 /* | |
626 * Now we want to bring up the link. | |
627 */ | |
628 demand_block(); | |
629 info("Starting link"); | |
630 } | |
631 | |
632 new_phase(doing_callback ? PHASE_CALLINGBACK : PHASE_SERIALCONN); | |
633 | |
634 /* | |
635 * Get a pty master/slave pair if the pty, notty, socket, | |
636 * or record options were specified. | |
637 */ | |
638 (void) strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); | |
639 pty_master = -1; | |
640 pty_slave = -1; | |
641 if (using_pty || record_file != NULL) { | |
642 if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) { | |
643 error("Couldn't allocate pseudo-tty"); | |
644 status = EXIT_FATAL_ERROR; | |
645 goto fail; | |
646 } | |
647 set_up_tty(pty_slave, 1); | |
648 } | |
649 | |
650 /* | |
651 * Lock the device if we've been asked to. | |
652 */ | |
653 status = EXIT_LOCK_FAILED; | |
654 if (lockflag && !privopen && !direct_tty) { | |
655 if (lock(devnam) < 0) | |
656 goto fail; | |
657 locked = 1; | |
658 } | |
659 | |
660 /* | |
661 * Open the serial device and set it up to be the ppp interface. | |
662 * First we open it in non-blocking mode so we can set the | |
663 * various termios flags appropriately. If we aren't dialling | |
664 * out and we want to use the modem lines, we reopen it later | |
665 * in order to wait for the carrier detect signal from the modem. | |
666 */ | |
667 hungup = 0; | |
668 kill_link = 0; | |
669 connector = doing_callback? callback_script: connect_script; | |
670 if (direct_tty) { | |
671 ttyfd = 0; | |
672 } else if (devnam[0] != '\0') { | |
673 for (;;) { | |
674 /* If the user specified the device name, become the | |
675 user before opening it. */ | |
676 int err; | |
677 if (!devnam_info.priv && !privopen) | |
678 (void) seteuid(uid); | |
679 if ((ttyfd = sys_extra_fd()) < 0) | |
680 ttyfd = open(devnam, O_NONBLOCK | O_RDWR); | |
681 err = errno; | |
682 if (!devnam_info.priv && !privopen) | |
683 (void) seteuid(0); | |
684 if (ttyfd >= 0) | |
685 break; | |
686 errno = err; | |
687 if (err != EINTR) { | |
688 error("Failed to open %s: %m", devnam); | |
689 status = EXIT_OPEN_FAILED; | |
690 } | |
691 if (!persist || err != EINTR) | |
692 goto fail; | |
693 } | |
694 if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 | |
695 || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) | |
696 warn("Couldn't reset non-blocking mode on device: %m"); | |
697 | |
698 /* | |
699 * Do the equivalent of `mesg n' to stop broadcast messages. | |
700 */ | |
701 if (fstat(ttyfd, &statbuf) < 0 | |
702 || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { | |
703 warn("Couldn't restrict write permissions to %s: %m", devnam); | |
704 } else | |
705 tty_mode = statbuf.st_mode; | |
706 | |
707 /* | |
708 * Set line speed, flow control, etc. | |
709 * If we have a non-null connection or initializer script, | |
710 * on most systems we set CLOCAL for now so that we can talk | |
711 * to the modem before carrier comes up. But this has the | |
712 * side effect that we might miss it if CD drops before we | |
713 * get to clear CLOCAL below. On systems where we can talk | |
714 * successfully to the modem with CLOCAL clear and CD down, | |
715 * we could clear CLOCAL at this point. | |
716 */ | |
717 set_up_tty(ttyfd, ((connector != NULL && connector[0] != '\0') | |
718 || initializer != NULL)); | |
719 real_ttyfd = ttyfd; | |
720 } | |
721 | |
722 /* | |
723 * If the pty, socket, notty and/or record option was specified, | |
724 * start up the character shunt now. | |
725 */ | |
726 status = EXIT_PTYCMD_FAILED; | |
727 if (ptycommand != NULL) { | |
728 if (record_file != NULL) { | |
729 int ipipe[2], opipe[2], ok; | |
730 | |
731 if (pipe(ipipe) < 0 || pipe(opipe) < 0) | |
732 fatal("Couldn't create pipes for record option: %m"); | |
733 dbglog("starting charshunt for pty option"); | |
734 ok = device_script(ptycommand, opipe[0], ipipe[1], 1, | |
735 "record") == 0 && start_charshunt(ipipe[0], opipe[1]); | |
736 (void) close(ipipe[0]); | |
737 (void) close(ipipe[1]); | |
738 (void) close(opipe[0]); | |
739 (void) close(opipe[1]); | |
740 if (!ok) | |
741 goto fail; | |
742 } else { | |
743 if (device_script(ptycommand, pty_master, pty_master, 1, | |
744 "pty") < 0) | |
745 goto fail; | |
746 ttyfd = pty_slave; | |
747 (void) close(pty_master); | |
748 pty_master = -1; | |
749 } | |
750 } else if (pty_socket != NULL) { | |
751 int fd = open_socket(pty_socket); | |
752 if (fd < 0) | |
753 goto fail; | |
754 dbglog("starting charshunt for socket option"); | |
755 if (!start_charshunt(fd, fd)) | |
756 goto fail; | |
757 } else if (notty) { | |
758 dbglog("starting charshunt for notty option"); | |
759 if (!start_charshunt(0, 1)) | |
760 goto fail; | |
761 } else if (record_file != NULL) { | |
762 dbglog("starting charshunt for record option"); | |
763 if (!start_charshunt(ttyfd, ttyfd)) | |
764 goto fail; | |
765 } | |
766 | |
767 /* run connection script */ | |
768 if (((connector != NULL) && (connector[0] != '\0')) || initializer) { | |
769 if (real_ttyfd != -1) { | |
770 /* XXX do this if doing_callback == CALLBACK_DIALIN? */ | |
771 if (!default_device && modem && !direct_tty) { | |
772 setdtr(real_ttyfd, 0); /* in case modem is off hook */ | |
773 (void) sleep(1); | |
774 setdtr(real_ttyfd, 1); | |
775 } | |
776 } | |
777 | |
778 if ((initializer != NULL) && (initializer[0] != '\0')) { | |
779 if (device_script(initializer, ttyfd, ttyfd, 0, "init") < 0) { | |
780 error("Initializer script failed"); | |
781 status = EXIT_INIT_FAILED; | |
782 goto fail; | |
783 } | |
784 if (kill_link) | |
785 goto disconnect; | |
786 | |
787 info("Serial port initialized."); | |
788 } | |
789 | |
790 if ((connector != NULL) && (connector[0] != '\0')) { | |
791 if (device_script(connector, ttyfd, ttyfd, 0, "connect") < 0) { | |
792 error("Connect script failed"); | |
793 status = EXIT_CONNECT_FAILED; | |
794 goto fail; | |
795 } | |
796 if (kill_link) | |
797 goto disconnect; | |
798 | |
799 info("Serial connection established."); | |
800 } | |
801 | |
802 /* | |
803 * Clear CLOCAL if modem option -- we now have carrier | |
804 * established, and we should respect loss of carrier. | |
805 */ | |
806 if (real_ttyfd != -1) | |
807 set_up_tty(real_ttyfd, 0); | |
808 | |
809 if (doing_callback == CALLBACK_DIALIN) | |
810 connector = NULL; | |
811 } | |
812 | |
813 /* reopen tty if necessary to wait for carrier */ | |
814 if (connector == NULL && modem && devnam[0] != '\0' && !direct_tty) { | |
815 for (;;) { | |
816 if ((i = open(devnam, O_RDWR)) >= 0) | |
817 break; | |
818 if (errno != EINTR) { | |
819 error("Failed to reopen %s: %m", devnam); | |
820 status = EXIT_OPEN_FAILED; | |
821 } | |
822 if (!persist || errno != EINTR || hungup || kill_link) | |
823 goto fail; | |
824 } | |
825 (void) close(i); | |
826 } | |
827 | |
828 (void) slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); | |
829 script_setenv("SPEED", numbuf, 0); | |
830 | |
831 /* run welcome script, if any */ | |
832 if ((welcomer != NULL) && (welcomer[0] != '\0')) { | |
833 if (device_script(welcomer, ttyfd, ttyfd, 0, "welcome") < 0) | |
834 warn("Welcome script failed"); | |
835 } | |
836 | |
837 /* set up the serial device as a ppp interface */ | |
838 #ifdef HAVE_MULTILINK | |
839 (void) tdb_writelock(pppdb); | |
840 #endif | |
841 fd_ppp = establish_ppp(ttyfd); | |
842 if (fd_ppp < 0) { | |
843 #ifdef HAVE_MULTILINK | |
844 (void) tdb_writeunlock(pppdb); | |
845 #endif | |
846 status = EXIT_FATAL_ERROR; | |
847 goto disconnect; | |
848 } | |
849 | |
850 if (!demand && ifunit >= 0) | |
851 set_ifunit(1); | |
852 #ifdef HAVE_MULTILINK | |
853 (void) tdb_writeunlock(pppdb); | |
854 #endif | |
855 | |
856 /* | |
857 * Start opening the connection and wait for | |
858 * incoming events (reply, timeout, etc.). | |
859 */ | |
860 notice("Connect: %s <--> %s", ifname, ppp_devnam); | |
861 (void) gettimeofday(&start_time, NULL); | |
862 link_stats_valid = 0; | |
863 script_unsetenv("CONNECT_TIME"); | |
864 script_unsetenv("BYTES_SENT"); | |
865 script_unsetenv("BYTES_RCVD"); | |
866 lcp_lowerup(0); | |
867 | |
868 /* Mostly for accounting purposes */ | |
869 new_phase(PHASE_CONNECTED); | |
870 | |
871 /* | |
872 * If we are initiating this connection, wait for a short | |
873 * time for something from the peer. This can avoid bouncing | |
874 * our packets off his tty before he has it set up. | |
875 */ | |
876 add_fd(fd_ppp); | |
877 if (connect_delay != 0 && (connector != NULL || ptycommand != NULL)) { | |
878 struct timeval t; | |
879 t.tv_sec = connect_delay / 1000; | |
880 t.tv_usec = connect_delay % 1000; | |
881 wait_input(&t); | |
882 } | |
883 | |
884 lcp_open(0); /* Start protocol */ | |
885 open_ccp_flag = 0; | |
886 status = EXIT_NEGOTIATION_FAILED; | |
887 new_phase(PHASE_ESTABLISH); | |
888 while (phase != PHASE_DEAD) { | |
889 if (sigsetjmp(sigjmp, 1) == 0) { | |
890 (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); | |
891 if (kill_link || open_ccp_flag || got_sigchld) { | |
892 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
893 } else { | |
894 waiting = 1; | |
895 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
896 wait_input(timeleft(&timo)); | |
897 } | |
898 } | |
899 waiting = 0; | |
900 calltimeout(); | |
901 get_input(); | |
902 if (kill_link) { | |
903 lcp_close(0, "User request"); | |
904 kill_link = 0; | |
905 } | |
906 if (open_ccp_flag) { | |
907 if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) { | |
908 /* Uncloak ourselves. */ | |
909 ccp_fsm[0].flags &= ~OPT_SILENT; | |
910 (*ccp_protent.open)(0); | |
911 } | |
912 open_ccp_flag = 0; | |
913 } | |
914 if (got_sigchld) | |
915 (void) reap_kids(0); /* Don't leave dead kids lying around */ | |
916 } | |
917 | |
918 /* | |
919 * Print connect time and statistics. | |
920 */ | |
921 if (link_stats_valid) { | |
922 int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ | |
923 info("Connect time %d.%d minutes.", t/10, t%10); | |
924 info("Sent %" PPP_COUNTER_F " bytes (%" PPP_COUNTER_F | |
925 " packets), received %" PPP_COUNTER_F " bytes (%" PPP_COUNTER_F | |
926 " packets).", | |
927 link_stats.bytes_out, link_stats.pkts_out, | |
928 link_stats.bytes_in, link_stats.pkts_in); | |
929 } | |
930 | |
931 /* | |
932 * Delete pid file before disestablishing ppp. Otherwise it | |
933 * can happen that another pppd gets the same unit and then | |
934 * we delete its pid file. | |
935 */ | |
936 if (!demand) { | |
937 if (pidfilename[0] != '\0' | |
938 && unlink(pidfilename) < 0 && errno != ENOENT) | |
939 warn("unable to delete pid file %s: %m", pidfilename); | |
940 pidfilename[0] = '\0'; | |
941 } | |
942 | |
943 /* | |
944 * If we may want to bring the link up again, transfer | |
945 * the ppp unit back to the loopback. Set the | |
946 * real serial device back to its normal mode of operation. | |
947 */ | |
948 remove_fd(fd_ppp); | |
949 clean_check(); | |
950 if (demand) | |
951 restore_loop(); | |
952 disestablish_ppp(ttyfd); | |
953 fd_ppp = -1; | |
954 if (!hungup) | |
955 lcp_lowerdown(0); | |
956 if (!demand) | |
957 script_unsetenv("IFNAME"); | |
958 | |
959 /* | |
960 * Run disconnector script, if requested. | |
961 * XXX we may not be able to do this if the line has hung up! | |
962 */ | |
963 disconnect: | |
964 if ((disconnect_script != NULL) && (disconnect_script[0] != '\0') && | |
965 !hungup) { | |
966 new_phase(PHASE_DISCONNECT); | |
967 if (real_ttyfd >= 0) | |
968 set_up_tty(real_ttyfd, 1); | |
969 if (device_script(disconnect_script, ttyfd, ttyfd, 0, | |
970 "disconnect") < 0) { | |
971 warn("disconnect script failed"); | |
972 } else { | |
973 info("Serial link disconnected."); | |
974 } | |
975 } | |
976 | |
977 fail: | |
978 if (pty_master >= 0) | |
979 (void) close(pty_master); | |
980 if (pty_slave >= 0) { | |
981 (void) close(pty_slave); | |
982 pty_slave = -1; | |
983 } | |
984 if (real_ttyfd >= 0) | |
985 close_tty(); | |
986 if (locked) { | |
987 locked = 0; | |
988 unlock(); | |
989 } | |
990 | |
991 if (!demand) { | |
992 if (pidfilename[0] != '\0' | |
993 && unlink(pidfilename) < 0 && errno != ENOENT) | |
994 warn("unable to delete pid file %s: %m", pidfilename); | |
995 pidfilename[0] = '\0'; | |
996 } | |
997 | |
998 if (!persist || (maxfail > 0 && unsuccess >= maxfail)) | |
999 break; | |
1000 | |
1001 kill_link = 0; | |
1002 if (demand) | |
1003 demand_discard(); | |
1004 t = need_holdoff? holdoff: 0; | |
1005 if (holdoff_hook != NULL) | |
1006 t = (*holdoff_hook)(); | |
1007 if (t > 0) { | |
1008 new_phase(PHASE_HOLDOFF); | |
1009 TIMEOUT(holdoff_end, NULL, t); | |
1010 do { | |
1011 if (sigsetjmp(sigjmp, 1) == 0) { | |
1012 (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); | |
1013 if (kill_link || got_sigchld) { | |
1014 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
1015 } else { | |
1016 waiting = 1; | |
1017 (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); | |
1018 wait_input(timeleft(&timo)); | |
1019 } | |
1020 } | |
1021 waiting = 0; | |
1022 calltimeout(); | |
1023 if (kill_link) { | |
1024 kill_link = 0; | |
1025 new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ | |
1026 } | |
1027 if (got_sigchld) | |
1028 (void) reap_kids(0); | |
1029 } while (phase == PHASE_HOLDOFF); | |
1030 if (!persist) | |
1031 break; | |
1032 } | |
1033 } | |
1034 | |
1035 /* Wait for scripts to finish */ | |
1036 final_reap(); | |
1037 | |
1038 die(status); | |
1039 return (0); | |
1040 } | |
1041 | |
1042 /* | |
1043 * setup_signals - initialize signal handling. | |
1044 */ | |
1045 static void | |
1046 setup_signals() | |
1047 { | |
1048 struct sigaction sa; | |
1049 | |
1050 /* | |
1051 * Compute mask of all interesting signals and install signal handlers | |
1052 * for each. Only one signal handler may be active at a time. Therefore, | |
1053 * all other signals should be masked when any handler is executing. | |
1054 */ | |
1055 (void) sigemptyset(&main_sigmask); | |
1056 (void) sigaddset(&main_sigmask, SIGHUP); | |
1057 (void) sigaddset(&main_sigmask, SIGINT); | |
1058 (void) sigaddset(&main_sigmask, SIGTERM); | |
1059 (void) sigaddset(&main_sigmask, SIGCHLD); | |
1060 (void) sigaddset(&main_sigmask, SIGUSR2); | |
1061 | |
1062 #define SIGNAL(s, handler) if (1) { \ | |
1063 sa.sa_handler = handler; \ | |
1064 if (sigaction(s, &sa, NULL) < 0) \ | |
1065 fatal("Couldn't establish signal handler (%d): %m", s); \ | |
1066 } else ((void)0) | |
1067 | |
1068 sa.sa_mask = main_sigmask; | |
1069 sa.sa_flags = 0; | |
1070 /*CONSTANTCONDITION*/ SIGNAL(SIGHUP, hup); /* Hangup */ | |
1071 /*CONSTANTCONDITION*/ SIGNAL(SIGINT, term); /* Interrupt */ | |
1072 /*CONSTANTCONDITION*/ SIGNAL(SIGTERM, term); /* Terminate */ | |
1073 /*CONSTANTCONDITION*/ SIGNAL(SIGCHLD, chld); | |
1074 | |
1075 /*CONSTANTCONDITION*/ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */ | |
1076 /*CONSTANTCONDITION*/ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */ | |
1077 | |
1078 /* | |
1079 * Install a handler for other signals which would otherwise | |
1080 * cause pppd to exit without cleaning up. | |
1081 */ | |
1082 /*CONSTANTCONDITION*/ SIGNAL(SIGABRT, bad_signal); | |
1083 /*CONSTANTCONDITION*/ SIGNAL(SIGALRM, bad_signal); | |
1084 /*CONSTANTCONDITION*/ SIGNAL(SIGFPE, bad_signal); | |
1085 /*CONSTANTCONDITION*/ SIGNAL(SIGILL, bad_signal); | |
1086 /*CONSTANTCONDITION*/ SIGNAL(SIGPIPE, bad_signal); | |
1087 /*CONSTANTCONDITION*/ SIGNAL(SIGQUIT, bad_signal); | |
1088 #ifndef DEBUG | |
1089 /*CONSTANTCONDITION*/ SIGNAL(SIGSEGV, bad_signal); | |
1090 #endif | |
1091 #ifdef SIGBUS | |
1092 /*CONSTANTCONDITION*/ SIGNAL(SIGBUS, bad_signal); | |
1093 #endif | |
1094 #ifdef SIGEMT | |
1095 /*CONSTANTCONDITION*/ SIGNAL(SIGEMT, bad_signal); | |
1096 #endif | |
1097 #ifdef SIGPOLL | |
1098 /*CONSTANTCONDITION*/ SIGNAL(SIGPOLL, bad_signal); | |
1099 #endif | |
1100 #ifdef SIGPROF | |
1101 /*CONSTANTCONDITION*/ SIGNAL(SIGPROF, bad_signal); | |
1102 #endif | |
1103 #ifdef SIGSYS | |
1104 /*CONSTANTCONDITION*/ SIGNAL(SIGSYS, bad_signal); | |
1105 #endif | |
1106 #ifdef SIGTRAP | |
1107 /*CONSTANTCONDITION*/ SIGNAL(SIGTRAP, bad_signal); | |
1108 #endif | |
1109 #ifdef SIGVTALRM | |
1110 /*CONSTANTCONDITION*/ SIGNAL(SIGVTALRM, bad_signal); | |
1111 #endif | |
1112 #ifdef SIGXCPU | |
1113 /*CONSTANTCONDITION*/ SIGNAL(SIGXCPU, bad_signal); | |
1114 #endif | |
1115 #ifdef SIGXFSZ | |
1116 /*CONSTANTCONDITION*/ SIGNAL(SIGXFSZ, bad_signal); | |
1117 #endif | |
1118 | |
1119 /* | |
1120 * Apparently we can get a SIGPIPE when we call syslog, if | |
1121 * syslogd has died and been restarted. Ignoring it seems | |
1122 * be sufficient. | |
1123 */ | |
1124 (void) signal(SIGPIPE, SIG_IGN); | |
1125 } | |
1126 | |
1127 /* | |
1128 * set_ifunit - do things we need to do once we know which ppp | |
1129 * unit we are using. | |
1130 */ | |
1131 void | |
1132 set_ifunit(iskey) | |
1133 int iskey; | |
1134 { | |
1135 sys_ifname(); | |
1136 info("Using interface %s", ifname); | |
1137 script_setenv("IFNAME", ifname, iskey); | |
1138 if (iskey) { | |
1139 create_pidfile(); /* write pid to file */ | |
1140 create_linkpidfile(); | |
1141 } | |
1142 } | |
1143 | |
1144 /* | |
1145 * detach - detach us from the controlling terminal. | |
1146 */ | |
1147 void | |
1148 detach() | |
1149 { | |
1150 pid_t pid; | |
1151 char numbuf[16]; | |
1152 | |
1153 if (detached) | |
1154 return; | |
1155 if ((pid = fork()) == (pid_t)-1) { | |
1156 error("Couldn't detach (fork failed: %m)"); | |
1157 die(1); /* or just return? */ | |
1158 } | |
1159 if (pid != (pid_t)0) { | |
1160 /* parent */ | |
1161 if (locked) | |
1162 (void) relock(pid); | |
1163 exit(0); /* parent dies */ | |
1164 } | |
1165 (void) setsid(); | |
1166 /* | |
1167 * Fork again to relinquish session leadership. This is needed | |
1168 * to prevent the daemon from acquiring controlling terminal. | |
1169 */ | |
1170 if ((pid = fork()) == (pid_t)-1) { | |
1171 error("Couldn't detach (second fork failed: %m)"); | |
1172 die(1); /* or just return? */ | |
1173 } | |
1174 if (pid != (pid_t)0) { | |
1175 /* parent */ | |
1176 if (locked) | |
1177 (void) relock(pid); | |
1178 exit(0); /* parent dies */ | |
1179 } | |
1180 (void) chdir("/"); | |
1181 (void) close(0); | |
1182 (void) close(1); | |
1183 (void) close(2); | |
1184 detached = 1; | |
1185 if (!log_to_file && !log_to_specific_fd) | |
1186 log_to_fd = -1; | |
1187 /* update pid files if they have been written already */ | |
1188 if (pidfilename[0] != '\0') | |
1189 create_pidfile(); | |
1190 if (linkpidfile[0] != '\0') | |
1191 create_linkpidfile(); | |
1192 (void) slprintf(numbuf, sizeof(numbuf), "%d", getpid()); | |
1193 script_setenv("PPPD_PID", numbuf, 1); | |
1194 } | |
1195 | |
1196 /* | |
1197 * reopen_log - (re)open our connection to syslog. | |
1198 */ | |
1199 void | |
1200 reopen_log() | |
1201 { | |
1202 #ifdef ULTRIX | |
1203 openlog("pppd", LOG_PID); | |
1204 #else | |
1205 openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); | |
1206 (void) setlogmask(LOG_UPTO(LOG_INFO)); | |
1207 #endif | |
1208 } | |
1209 | |
1210 /* | |
1211 * Create a file containing our process ID. | |
1212 */ | |
1213 static void | |
1214 create_pidfile() | |
1215 { | |
1216 FILE *pidfile; | |
1217 | |
1218 (void) slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid", | |
1219 _PATH_VARRUN, ifname); | |
1220 if ((pidfile = fopen(pidfilename, "w")) != NULL) { | |
1221 (void) fprintf(pidfile, "%u\n", (unsigned)getpid()); | |
1222 (void) fclose(pidfile); | |
1223 } else { | |
1224 error("Failed to create pid file %s: %m", pidfilename); | |
1225 pidfilename[0] = '\0'; | |
1226 } | |
1227 } | |
1228 | |
1229 static void | |
1230 create_linkpidfile() | |
1231 { | |
1232 FILE *pidfile; | |
1233 | |
1234 if (linkname[0] == '\0') | |
1235 return; | |
1236 script_setenv("LINKNAME", linkname, 1); | |
1237 (void) slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid", | |
1238 _PATH_VARRUN, linkname); | |
1239 if ((pidfile = fopen(linkpidfile, "w")) != NULL) { | |
1240 (void) fprintf(pidfile, "%u\n", (unsigned)getpid()); | |
1241 if (ifname[0] != '\0') | |
1242 (void) fprintf(pidfile, "%s\n", ifname); | |
1243 (void) fclose(pidfile); | |
1244 } else { | |
1245 error("Failed to create pid file %s: %m", linkpidfile); | |
1246 linkpidfile[0] = '\0'; | |
1247 } | |
1248 } | |
1249 | |
1250 /* | |
1251 * holdoff_end - called via a timeout when the holdoff period ends. | |
1252 */ | |
1253 /*ARGSUSED*/ | |
1254 static void | |
1255 holdoff_end(arg) | |
1256 void *arg; | |
1257 { | |
1258 new_phase(PHASE_DORMANT); | |
1259 } | |
1260 | |
1261 /* List of protocol names, to make our messages a little more informative. */ | |
1262 struct protocol_list { | |
1263 u_short proto; | |
1264 const char *name; | |
1265 } protocol_list[] = { | |
1266 { 0x21, "IP" }, | |
1267 { 0x23, "OSI Network Layer" }, | |
1268 { 0x25, "Xerox NS IDP" }, | |
1269 { 0x27, "DECnet Phase IV" }, | |
1270 { 0x29, "Appletalk" }, | |
1271 { 0x2b, "Novell IPX" }, | |
1272 { 0x2d, "VJ compressed TCP/IP" }, | |
1273 { 0x2f, "VJ uncompressed TCP/IP" }, | |
1274 { 0x31, "Bridging PDU" }, | |
1275 { 0x33, "Stream Protocol ST-II" }, | |
1276 { 0x35, "Banyan Vines" }, | |
1277 { 0x37, "Old VJ compressed TCP/IP" }, | |
1278 { 0x39, "AppleTalk EDDP" }, | |
1279 { 0x3b, "AppleTalk SmartBuffered" }, | |
1280 { 0x3d, "Multilink" }, | |
1281 { 0x3f, "NetBIOS Frame" }, | |
1282 { 0x41, "Cisco LAN Extension" }, | |
1283 { 0x43, "Ascom Timeplex" }, | |
1284 { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, | |
1285 { 0x47, "DCA Remote Lan" }, | |
1286 { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, | |
1287 { 0x4b, "SNA over 802.2" }, | |
1288 { 0x4d, "SNA" }, | |
1289 { 0x4f, "IP6 Header Compression" }, | |
1290 { 0x51, "KNX Bridging" }, | |
1291 { 0x53, "Encrypted" }, | |
1292 { 0x55, "per-link encrypted" }, | |
1293 { 0x57, "IPv6" }, | |
1294 { 0x59, "PPP Muxing" }, | |
1295 { 0x6f, "Stampede Bridging" }, | |
1296 { 0x73, "MP+" }, | |
1297 { 0xc1, "STMF" }, | |
1298 { 0xfb, "per-link compressed" }, | |
1299 { 0xfd, "compressed datagram" }, | |
1300 { 0x0201, "802.1d Hello Packets" }, | |
1301 { 0x0203, "IBM Source Routing BPDU" }, | |
1302 { 0x0205, "DEC LANBridge100 Spanning Tree" }, | |
1303 { 0x0207, "Cisco Discovery Protocol" }, | |
1304 { 0x0231, "Luxcom" }, | |
1305 { 0x0233, "Sigma Network Systems" }, | |
1306 { 0x0235, "Apple Client Server Protocol" }, | |
1307 { 0x0281, "MPLS Unicast" }, | |
1308 { 0x0283, "MPLS Multicast" }, | |
1309 { 0x0285, "IEEE p1284.4" }, | |
1310 { 0x0287, "ETSI TETRA TNP1" }, | |
1311 { 0x4021, "Stacker LZS" }, | |
1312 { 0x8021, "Internet Protocol Control Protocol" }, | |
1313 { 0x8023, "OSI Network Layer Control Protocol" }, | |
1314 { 0x8025, "Xerox NS IDP Control Protocol" }, | |
1315 { 0x8027, "DECnet Phase IV Control Protocol" }, | |
1316 { 0x8029, "Appletalk Control Protocol" }, | |
1317 { 0x802b, "Novell IPX Control Protocol" }, | |
1318 { 0x8031, "Bridging Control Protocol" }, | |
1319 { 0x8033, "Stream Protocol Control Protocol" }, | |
1320 { 0x8035, "Banyan Vines Control Protocol" }, | |
1321 { 0x803f, "NetBIOS Frames Control Protocol" }, | |
1322 { 0x8041, "Cisco LAN Extension Control Protocol" }, | |
1323 { 0x8043, "Ascom Timeplex Control Protocol" }, | |
1324 { 0x8045, "Fujitsu LBLB Control Protocol" }, | |
1325 { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, | |
1326 { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, | |
1327 { 0x804b, "SNA over 802.2 Control Protocol" }, | |
1328 { 0x804d, "SNA Control Protocol" }, | |
1329 { 0x8051, "KNX Bridging Control Protocol" }, | |
1330 { 0x8053, "Encryption Control Protocol" }, | |
1331 { 0x8055, "Per-link Encryption Control Protocol" }, | |
1332 { 0x8057, "IPv6 Control Protocol" }, | |
1333 { 0x806f, "Stampede Bridging Control Protocol" }, | |
1334 { 0x80c1, "STMF Control Protocol" }, | |
1335 { 0x80fb, "Per-link Compression Control Protocol" }, | |
1336 { 0x80fd, "Compression Control Protocol" }, | |
1337 { 0x8207, "Cisco Discovery Control Protocol" }, | |
1338 { 0x8235, "Apple Client Server Control Protocol" }, | |
1339 { 0x8281, "MPLS Control Protocol" }, | |
1340 { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, | |
1341 { 0xc021, "Link Control Protocol" }, | |
1342 { 0xc023, "Password Authentication Protocol" }, | |
1343 { 0xc025, "Link Quality Report" }, | |
1344 { 0xc027, "Shiva Password Authentication Protocol" }, | |
1345 { 0xc029, "CallBack Control Protocol (CBCP)" }, | |
1346 { 0xc02b, "Bandwidth Allocation Control Protocol" }, | |
1347 { 0xc02d, "BAP" }, | |
1348 { 0xc081, "Container Control Protocol" }, | |
1349 { 0xc223, "Challenge Handshake Authentication Protocol" }, | |
1350 { 0xc227, "Extensible Authentication Protocol" }, | |
1351 { 0xc281, "Funk Proprietary Authentication Protocol" }, | |
1352 { 0, NULL }, | |
1353 }; | |
1354 | |
1355 /* | |
1356 * protocol_name - find a name for a PPP protocol. | |
1357 */ | |
1358 const char * | |
1359 protocol_name(proto) | |
1360 int proto; | |
1361 { | |
1362 struct protocol_list *lp; | |
1363 | |
1364 for (lp = protocol_list; lp->proto != 0; ++lp) | |
1365 if (proto == lp->proto) | |
1366 return (lp->name); | |
1367 return (NULL); | |
1368 } | |
1369 | |
1370 static const char *phase_names[] = { PHASE__NAMES }; | |
1371 | |
1372 const char * | |
1373 phase_name(pval) | |
1374 int pval; | |
1375 { | |
1376 static char buf[32]; | |
1377 | |
1378 if (pval < 0 || pval >= Dim(phase_names)) { | |
1379 (void) slprintf(buf, sizeof (buf), "unknown %d", pval); | |
1380 return ((const char *)buf); | |
1381 } | |
1382 return (phase_names[pval]); | |
1383 } | |
1384 | |
1385 /* | |
1386 * get_input - called when incoming data is available. | |
1387 */ | |
1388 static void | |
1389 get_input() | |
1390 { | |
1391 int len, i; | |
1392 u_char *p; | |
1393 u_short protocol; | |
1394 struct protent *protp; | |
1395 const char *pname; | |
1396 | |
1397 p = inpacket_buf; /* point to beginning of packet buffer */ | |
1398 | |
1399 len = read_packet(inpacket_buf); | |
1400 if (len < 0) | |
1401 return; | |
1402 | |
1403 if (len == 0) { | |
1404 notice("Modem hangup"); | |
1405 hungup = 1; | |
1406 status = EXIT_HANGUP; | |
1407 lcp_lowerdown(0); /* serial link is no longer available */ | |
1408 link_terminated(0); | |
1409 return; | |
1410 } | |
1411 | |
1412 if (debug /*&& (debugflags & DBG_INPACKET)*/) | |
1413 dbglog("rcvd %P", p, len); | |
1414 | |
1415 if (len < PPP_HDRLEN) { | |
1416 dbglog("Discarded short packet (%d < %d)", len, PPP_HDRLEN); | |
1417 return; | |
1418 } | |
1419 | |
1420 p += 2; /* Skip address and control */ | |
1421 GETSHORT(protocol, p); | |
1422 len -= PPP_HDRLEN; | |
1423 | |
1424 pname = debug ? NULL : protocol_name(protocol); | |
1425 | |
1426 /* | |
1427 * Toss all non-LCP packets unless LCP is in Opened state and | |
1428 * discard non-authentication protocols if we're not yet | |
1429 * authenticated. | |
1430 */ | |
1431 if ((protocol != PPP_LCP && | |
1432 (phase < PHASE_AUTHENTICATE || phase > PHASE_RUNNING)) || | |
1433 (phase <= PHASE_AUTHENTICATE && | |
1434 !(protocol == PPP_LCP || protocol == PPP_LQR || | |
1435 protocol == PPP_PAP || protocol == PPP_CHAP))) { | |
1436 if (pname == NULL) | |
1437 dbglog("Discarded proto 0x%x in %s phase", | |
1438 protocol, phase_name(phase)); | |
1439 else | |
1440 dbglog("Discarded %s (0x%x) in %s phase", | |
1441 pname, protocol, phase_name(phase)); | |
1442 return; | |
1443 } | |
1444 | |
1445 /* | |
1446 * Upcall the proper protocol input routine. | |
1447 */ | |
1448 for (i = 0; (protp = protocols[i]) != NULL; ++i) { | |
1449 if (protp->protocol == protocol && protp->enabled_flag) { | |
1450 (*protp->input)(0, p, len); | |
1451 return; | |
1452 } | |
1453 if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag | |
1454 && protp->datainput != NULL) { | |
1455 (*protp->datainput)(0, p, len); | |
1456 return; | |
1457 } | |
1458 } | |
1459 | |
1460 if (debug) { | |
1461 if (pname != NULL) | |
1462 warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); | |
1463 else | |
1464 warn("Unsupported protocol 0x%x received", protocol); | |
1465 } | |
1466 lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); | |
1467 } | |
1468 | |
1469 /* | |
1470 * new_phase - signal the start of a new phase of pppd's operation. | |
1471 */ | |
1472 void | |
1473 new_phase(p) | |
1474 int p; | |
1475 { | |
1476 if (new_phase_hook != NULL) | |
1477 (*new_phase_hook)(p, phase); | |
1478 phase = p; | |
1479 } | |
1480 | |
1481 /* | |
1482 * die - clean up state and exit with the specified status. | |
1483 */ | |
1484 void | |
1485 die(status) | |
1486 int status; | |
1487 { | |
1488 cleanup(); | |
1489 if (phase != PHASE_EXIT) { | |
1490 syslog(LOG_INFO, "Exit."); | |
1491 new_phase(PHASE_EXIT); | |
1492 } | |
1493 exit(status); | |
1494 } | |
1495 | |
1496 /* | |
1497 * cleanup - restore anything which needs to be restored before we exit | |
1498 */ | |
1499 static void | |
1500 cleanup() | |
1501 { | |
1502 sys_cleanup(); /* XXX: Need to check if this is okay after close_tty */ | |
1503 | |
1504 if (fd_ppp >= 0) { | |
1505 fd_ppp = -1; | |
1506 disestablish_ppp(ttyfd); | |
1507 } | |
1508 if (real_ttyfd >= 0) | |
1509 close_tty(); | |
1510 | |
1511 if (pidfilename[0] != '\0' && unlink(pidfilename) < 0 && errno != ENOENT) | |
1512 warn("unable to delete pid file %s: %m", pidfilename); | |
1513 pidfilename[0] = '\0'; | |
1514 if (linkpidfile[0] != '\0' && unlink(linkpidfile) < 0 && errno != ENOENT) | |
1515 warn("unable to delete pid file %s: %m", linkpidfile); | |
1516 linkpidfile[0] = '\0'; | |
1517 | |
1518 if (locked) { | |
1519 locked = 0; | |
1520 unlock(); | |
1521 } | |
1522 | |
1523 #ifdef HAVE_MULTILINK | |
1524 if (pppdb != NULL) { | |
1525 cleanup_db(); | |
1526 pppdb = NULL; | |
1527 } | |
1528 #endif | |
1529 } | |
1530 | |
1531 /* | |
1532 * close_tty - restore the terminal device and close it. | |
1533 */ | |
1534 static void | |
1535 close_tty() | |
1536 { | |
1537 int fd = real_ttyfd; | |
1538 | |
1539 real_ttyfd = -1; | |
1540 | |
1541 /* drop dtr to hang up */ | |
1542 if (!default_device && modem) { | |
1543 setdtr(fd, 0); | |
1544 /* | |
1545 * This sleep is in case the serial port has CLOCAL set by default, | |
1546 * and consequently will reassert DTR when we close the device. | |
1547 */ | |
1548 (void) sleep(1); | |
1549 } | |
1550 | |
1551 restore_tty(fd); | |
1552 | |
1553 if (tty_mode != (mode_t) -1) { | |
1554 if (fchmod(fd, tty_mode) != 0) { | |
1555 /* XXX if devnam is a symlink, this will change the link */ | |
1556 if (chmod(devnam, tty_mode) != 0) { | |
1557 error("Unable to chmod file %s: %m", devnam); | |
1558 } | |
1559 } | |
1560 } | |
1561 | |
1562 (void) close(fd); | |
1563 } | |
1564 | |
1565 /* | |
1566 * update_link_stats - get stats at link termination. | |
1567 */ | |
1568 void | |
1569 update_link_stats(u) | |
1570 int u; | |
1571 { | |
1572 struct timeval now; | |
1573 char numbuf[32]; | |
1574 | |
1575 if (gettimeofday(&now, NULL) >= 0) { | |
1576 link_connect_time = now.tv_sec - start_time.tv_sec; | |
1577 (void) slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time); | |
1578 script_setenv("CONNECT_TIME", numbuf, 0); | |
1579 } else { | |
1580 link_connect_time = 0; | |
1581 } | |
1582 | |
1583 if (get_ppp_stats(u, &link_stats)) { | |
1584 (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, | |
1585 link_stats.bytes_out); | |
1586 script_setenv("BYTES_SENT", numbuf, 0); | |
1587 (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, | |
1588 link_stats.bytes_in); | |
1589 script_setenv("BYTES_RCVD", numbuf, 0); | |
1590 (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, | |
1591 link_stats.pkts_in); | |
1592 script_setenv("PKTS_RCVD", numbuf, 0); | |
1593 (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, | |
1594 link_stats.pkts_out); | |
1595 script_setenv("PKTS_SENT", numbuf, 0); | |
1596 link_stats_valid = 1; | |
1597 } | |
1598 } | |
1599 | |
1600 | |
1601 struct callout { | |
1602 struct timeval c_time; /* time at which to call routine */ | |
1603 void *c_arg; /* argument to routine */ | |
1604 void (*c_func) __P((void *)); /* routine */ | |
1605 struct callout *c_next; | |
1606 }; | |
1607 | |
1608 static struct callout *callout = NULL; /* Callout list */ | |
1609 static struct timeval timenow; /* Current time */ | |
1610 | |
1611 /* | |
1612 * timeout - Schedule a timeout. | |
1613 * | |
1614 * Note that this timeout takes the number of seconds, NOT hz (as in | |
1615 * the kernel). | |
1616 */ | |
1617 void | |
1618 timeout(func, arg, time) | |
1619 void (*func) __P((void *)); | |
1620 void *arg; | |
1621 int time; | |
1622 { | |
1623 struct callout *newp, *p, **pp; | |
1624 | |
1625 MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time)); | |
1626 | |
1627 /* | |
1628 * Allocate timeout. | |
1629 */ | |
1630 if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) | |
1631 novm("callout structure for timeout."); | |
1632 newp->c_arg = arg; | |
1633 newp->c_func = func; | |
1634 (void) gettimeofday(&timenow, NULL); | |
1635 newp->c_time.tv_sec = timenow.tv_sec + time; | |
1636 newp->c_time.tv_usec = timenow.tv_usec; | |
1637 | |
1638 /* | |
1639 * Find correct place and link it in. | |
1640 */ | |
1641 for (pp = &callout; (p = *pp) != NULL; pp = &p->c_next) | |
1642 if (newp->c_time.tv_sec < p->c_time.tv_sec | |
1643 || (newp->c_time.tv_sec == p->c_time.tv_sec | |
1644 && newp->c_time.tv_usec < p->c_time.tv_usec)) | |
1645 break; | |
1646 newp->c_next = p; | |
1647 *pp = newp; | |
1648 } | |
1649 | |
1650 | |
1651 /* | |
1652 * untimeout - Unschedule a timeout. | |
1653 */ | |
1654 void | |
1655 untimeout(func, arg) | |
1656 void (*func) __P((void *)); | |
1657 void *arg; | |
1658 { | |
1659 struct callout **copp, *freep; | |
1660 | |
1661 MAINDEBUG(("Untimeout %p:%p.", func, arg)); | |
1662 | |
1663 /* | |
1664 * Find first matching timeout and remove it from the list. | |
1665 */ | |
1666 for (copp = &callout; (freep = *copp) != NULL; copp = &freep->c_next) | |
1667 if (freep->c_func == func && freep->c_arg == arg) { | |
1668 *copp = freep->c_next; | |
1669 free((char *) freep); | |
1670 break; | |
1671 } | |
1672 } | |
1673 | |
1674 | |
1675 /* | |
1676 * calltimeout - Call any timeout routines which are now due. | |
1677 */ | |
1678 static void | |
1679 calltimeout() | |
1680 { | |
1681 struct callout *p; | |
1682 | |
1683 while (callout != NULL) { | |
1684 p = callout; | |
1685 | |
1686 if (gettimeofday(&timenow, NULL) < 0) | |
1687 fatal("Failed to get time of day: %m"); | |
1688 if (!(p->c_time.tv_sec < timenow.tv_sec | |
1689 || (p->c_time.tv_sec == timenow.tv_sec | |
1690 && p->c_time.tv_usec <= timenow.tv_usec))) | |
1691 break; /* no, it's not time yet */ | |
1692 | |
1693 callout = p->c_next; | |
1694 (*p->c_func)(p->c_arg); | |
1695 | |
1696 free((char *) p); | |
1697 } | |
1698 } | |
1699 | |
1700 | |
1701 /* | |
1702 * timeleft - return the length of time until the next timeout is due. | |
1703 */ | |
1704 static struct timeval * | |
1705 timeleft(tvp) | |
1706 struct timeval *tvp; | |
1707 { | |
1708 if (callout == NULL) | |
1709 return (NULL); | |
1710 | |
1711 (void) gettimeofday(&timenow, NULL); | |
1712 tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec; | |
1713 tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec; | |
1714 if (tvp->tv_usec < 0) { | |
1715 tvp->tv_usec += 1000000; | |
1716 tvp->tv_sec -= 1; | |
1717 } | |
1718 if (tvp->tv_sec < 0) | |
1719 tvp->tv_sec = tvp->tv_usec = 0; | |
1720 | |
1721 return (tvp); | |
1722 } | |
1723 | |
1724 | |
1725 /* | |
1726 * kill_my_pg - send a signal to our process group, and ignore it ourselves. | |
1727 */ | |
1728 static void | |
1729 kill_my_pg(sig) | |
1730 int sig; | |
1731 { | |
1732 struct sigaction act, oldact; | |
1733 sigset_t mask; | |
1734 | |
1735 BZERO(&act, sizeof (act)); | |
1736 act.sa_handler = SIG_IGN; | |
1737 (void) sigemptyset(&mask); | |
1738 (void) sigaddset(&mask, sig); | |
1739 /* | |
1740 * Ignore signal 'sig' temporarily, before finally re-activating the | |
1741 * original handler. We need to do it in the following sequence, since | |
1742 * otherwise the signal handler for 'sig' will be called forever. | |
1743 */ | |
1744 if (sigaction(sig, &act, &oldact) < 0) { | |
1745 fatal("kill_my_pg: couldn't establish signal handler (%d): %m", sig); | |
1746 } | |
1747 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL); | |
1748 /* | |
1749 * Send signal 'sig' to all processes whose process group ID is equal | |
1750 * to the process group ID of the sender. | |
1751 */ | |
1752 (void) kill(0, sig); | |
1753 if (sigaction(sig, &oldact, NULL) < 0) { | |
1754 fatal("kill_my_pg: couldn't establish signal handler (%d): %m", sig); | |
1755 } | |
1756 } | |
1757 | |
1758 | |
1759 /* | |
1760 * hup - Catch SIGHUP signal. | |
1761 * | |
1762 * Indicates that the physical layer has been disconnected. | |
1763 * We don't rely on this indication; if the user has sent this | |
1764 * signal, we just take the link down. | |
1765 */ | |
1766 static void | |
1767 hup(sig) | |
1768 int sig; | |
1769 { | |
1770 info("Hangup (SIGHUP)"); | |
1771 kill_link = 1; | |
1772 if (status != EXIT_HANGUP) | |
1773 status = EXIT_USER_REQUEST; | |
1774 if (conn_running > 0) | |
1775 /* Send the signal to the [dis]connector process(es) also */ | |
1776 kill_my_pg(sig); | |
1777 if (charshunt_pid) | |
1778 (void) kill(charshunt_pid, sig); | |
1779 if (waiting) | |
1780 siglongjmp(sigjmp, 1); | |
1781 } | |
1782 | |
1783 | |
1784 /* | |
1785 * term - Catch SIGTERM signal and SIGINT signal (^C/del). | |
1786 * | |
1787 * Indicates that we should initiate a graceful disconnect and exit. | |
1788 */ | |
1789 /*ARGSUSED*/ | |
1790 static void | |
1791 term(sig) | |
1792 int sig; | |
1793 { | |
1794 info("Terminating on signal %d.", sig); | |
1795 persist = 0; /* don't try to restart */ | |
1796 kill_link = 1; | |
1797 status = EXIT_USER_REQUEST; | |
1798 if (conn_running > 0) | |
1799 /* Send the signal to the [dis]connector process(es) also */ | |
1800 kill_my_pg(sig); | |
1801 if (charshunt_pid) | |
1802 (void) kill(charshunt_pid, sig); | |
1803 if (waiting) | |
1804 siglongjmp(sigjmp, 1); | |
1805 } | |
1806 | |
1807 | |
1808 /* | |
1809 * chld - Catch SIGCHLD signal. | |
1810 * Sets a flag so we will call reap_kids in the mainline. | |
1811 */ | |
1812 /*ARGSUSED*/ | |
1813 static void | |
1814 chld(sig) | |
1815 int sig; | |
1816 { | |
1817 got_sigchld = 1; | |
1818 if (waiting) | |
1819 siglongjmp(sigjmp, 1); | |
1820 } | |
1821 | |
1822 /* | |
1823 * toggle_debug - Catch SIGUSR1 signal. | |
1824 * | |
1825 * Toggle debug flag. | |
1826 */ | |
1827 /*ARGSUSED*/ | |
1828 static void | |
1829 toggle_debug(sig) | |
1830 int sig; | |
1831 { | |
1832 if (debug) { | |
1833 print_ncpstate(0, NULL); | |
1834 dbglog("debug logging disabled"); | |
1835 (void) setlogmask(LOG_UPTO(LOG_WARNING)); | |
1836 debug = 0; | |
1837 } else { | |
1838 (void) setlogmask(LOG_UPTO(LOG_DEBUG)); | |
1839 dbglog("debug logging enabled"); | |
1840 print_ncpstate(0, NULL); | |
1841 debug = 1; | |
1842 } | |
1843 } | |
1844 | |
1845 | |
1846 /* | |
1847 * open_ccp - Catch SIGUSR2 signal. | |
1848 * | |
1849 * Try to (re)negotiate compression. | |
1850 */ | |
1851 /*ARGSUSED*/ | |
1852 static void | |
1853 open_ccp(sig) | |
1854 int sig; | |
1855 { | |
1856 open_ccp_flag = 1; | |
1857 if (waiting) | |
1858 siglongjmp(sigjmp, 1); | |
1859 } | |
1860 | |
1861 | |
1862 /* | |
1863 * bad_signal - We've caught a fatal signal. Clean up state and exit. | |
1864 */ | |
1865 static void | |
1866 bad_signal(sig) | |
1867 int sig; | |
1868 { | |
1869 static int crashed = 0; | |
1870 | |
1871 if (crashed) | |
1872 _exit(127); | |
1873 crashed = 1; | |
1874 error("Fatal signal %d", sig); | |
1875 if (conn_running > 0) | |
1876 kill_my_pg(SIGTERM); | |
1877 if (charshunt_pid) | |
1878 (void) kill(charshunt_pid, SIGTERM); | |
1879 die(127); | |
1880 } | |
1881 | |
1882 | |
1883 /* | |
1884 * device_script - run a program to talk to the serial device | |
1885 * (e.g. to run the connector or disconnector script). | |
1886 */ | |
1887 static int | |
1888 device_script(program, in, out, dont_wait, optname) | |
1889 char *program; | |
1890 int in, out; | |
1891 int dont_wait; | |
1892 char *optname; | |
1893 { | |
1894 pid_t pid; | |
1895 int status = -1; | |
1896 int errfd; | |
1897 int envpipe[2]; | |
1898 | |
1899 envpipe[0] = envpipe[1] = -1; | |
1900 if (!dont_wait && device_pipe_hook != NULL && pipe(envpipe) == -1) { | |
1901 error("Cannot create pipe for child: %m"); | |
1902 return (-1); | |
1903 } | |
1904 | |
1905 ++conn_running; | |
1906 pid = fork(); | |
1907 | |
1908 if (pid == (pid_t)-1) { | |
1909 --conn_running; | |
1910 error("Failed to create child process: %m"); | |
1911 return (-1); | |
1912 } | |
1913 | |
1914 if (pid == (pid_t)0) { | |
1915 sys_close(); | |
1916 closelog(); | |
1917 if (envpipe[0] >= 0) { | |
1918 if (envpipe[1] <= 2) | |
1919 envpipe[1] = dup(envpipe[1]); | |
1920 (void) close(envpipe[0]); | |
1921 } | |
1922 if (in == 2) { | |
1923 /* aargh!!! */ | |
1924 int newin = dup(in); | |
1925 if (in == out) | |
1926 out = newin; | |
1927 in = newin; | |
1928 } else if (out == 2) { | |
1929 out = dup(out); | |
1930 } | |
1931 if (log_to_fd >= 0) { | |
1932 if (log_to_fd != 2) { | |
1933 if (dup2(log_to_fd, 2) < 0) | |
1934 error("dup2(log_to_fd, STDERR) failed: %m"); | |
1935 } | |
1936 } else { | |
1937 (void) close(2); | |
1938 errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); | |
1939 if (errfd >= 0 && errfd != 2) { | |
1940 if (dup2(errfd, 2) < 0) | |
1941 error("dup2(errfd, STDERR) failed: %m"); | |
1942 (void) close(errfd); | |
1943 } | |
1944 } | |
1945 if (in != 0) { | |
1946 if (out == 0) | |
1947 out = dup(out); | |
1948 if (dup2(in, 0) < 0) | |
1949 error("dup2(in, STDIN) failed: %m"); | |
1950 } | |
1951 if (out != 1) { | |
1952 if (dup2(out, 1) < 0) | |
1953 error("dup2(out, STDOUT) failed: %m"); | |
1954 } | |
1955 if (envpipe[0] >= 0 && dup2(envpipe[1], 3) < 0) | |
1956 error("dup2(pipe, pipeout) failed: %m"); | |
1957 if (real_ttyfd > 2) | |
1958 (void) close(real_ttyfd); | |
1959 if (pty_master > 2) | |
1960 (void) close(pty_master); | |
1961 if (pty_slave > 2) { | |
1962 (void) close(pty_slave); | |
1963 pty_slave = -1; | |
1964 } | |
1965 (void) setuid(uid); | |
1966 if (getuid() != uid) { | |
1967 error("setuid failed"); | |
1968 exit(1); | |
1969 } | |
1970 (void) setgid(getgid()); | |
1971 if (script_env != NULL) { | |
1972 while (*script_env != NULL) { | |
1973 if (putenv(*script_env) == -1) | |
1974 warn("unable to set %s for %s: %m", *script_env, program); | |
1975 script_env++; | |
1976 } | |
1977 } | |
1978 (void) execl("/bin/sh", "sh", "-c", program, (char *)0); | |
1979 error("could not exec /bin/sh: %m"); | |
1980 exit(99); | |
1981 /* NOTREACHED */ | |
1982 } | |
1983 | |
1984 if (debug) | |
1985 dbglog("%s option: '%s' started (pid %d)", optname, program, pid); | |
1986 if (dont_wait) { | |
1987 record_child(pid, program, NULL, NULL); | |
1988 status = 0; | |
1989 } else { | |
1990 if (envpipe[0] >= 0) { | |
1991 (void) close(envpipe[1]); | |
1992 (*device_pipe_hook)(envpipe[0]); | |
1993 } | |
1994 while (waitpid(pid, &status, 0) < 0) { | |
1995 if (errno == EINTR) | |
1996 continue; | |
1997 fatal("error waiting for (dis)connection process: %m"); | |
1998 } | |
1999 if (envpipe[0] >= 0) | |
2000 (void) close(envpipe[0]); | |
2001 --conn_running; | |
2002 } | |
2003 | |
2004 return (status == 0 ? 0 : -1); | |
2005 } | |
2006 | |
2007 | |
2008 /* | |
2009 * run-program - execute a program with given arguments, | |
2010 * but don't wait for it. | |
2011 * If the program can't be executed, logs an error unless | |
2012 * must_exist is 0 and the program file doesn't exist. | |
2013 * Returns -1 if it couldn't fork, 0 if the file doesn't exist | |
2014 * or isn't an executable plain file, or the process ID of the child. | |
2015 * If done != NULL, (*done)(arg, int) will be called later (within | |
2016 * reap_kids) if this routine returns value > 0. | |
2017 */ | |
2018 pid_t | |
2019 run_program(prog, args, must_exist, done, arg) | |
2020 char *prog; | |
2021 char **args; | |
2022 int must_exist; | |
2023 void (*done) __P((void *arg, int status)); | |
2024 void *arg; | |
2025 { | |
2026 pid_t pid; | |
2027 struct stat sbuf; | |
2028 int retv; | |
2029 | |
2030 /* | |
2031 * First check if the file exists and is executable. | |
2032 * We don't use access() because that would use the | |
2033 * real user-id, which might not be root, and the script | |
2034 * might be accessible only to root. | |
2035 */ | |
2036 errno = EINVAL; | |
2037 if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode) | |
2038 || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { | |
2039 if (must_exist || errno != ENOENT) | |
2040 warn("Can't execute %s: %m", prog); | |
2041 return (0); | |
2042 } | |
2043 | |
2044 if (updown_script_hook != NULL) { | |
2045 retv = (*updown_script_hook)((const char ***)&args); | |
2046 if (retv == -1) { | |
2047 return (-1); | |
2048 } | |
2049 } | |
2050 | |
2051 pid = fork(); | |
2052 if (pid == (pid_t)-1) { | |
2053 error("Failed to create child process for %s: %m", prog); | |
2054 return (-1); | |
2055 } | |
2056 if (pid == (pid_t)0) { | |
2057 int new_fd; | |
2058 | |
2059 /* Leave the current location */ | |
2060 (void) setsid(); /* No controlling tty. */ | |
2061 (void) umask (S_IRWXG|S_IRWXO); | |
2062 (void) chdir ("/"); /* no current directory. */ | |
2063 (void) setuid(0); /* set real UID = root */ | |
2064 (void) setgid(getegid()); | |
2065 | |
2066 /* Ensure that nothing of our device environment is inherited. */ | |
2067 sys_close(); | |
2068 closelog(); | |
2069 (void) close(0); | |
2070 (void) close(1); | |
2071 (void) close(2); | |
2072 (void) close(ttyfd); /* tty interface to the ppp device */ | |
2073 if (real_ttyfd >= 0) | |
2074 (void) close(real_ttyfd); | |
2075 | |
2076 /* Don't pass handles to the PPP device, even by accident. */ | |
2077 new_fd = open (_PATH_DEVNULL, O_RDWR); | |
2078 if (new_fd >= 0) { | |
2079 if (new_fd != 0) { | |
2080 if (dup2(new_fd, 0) < 0) /* stdin <- /dev/null */ | |
2081 error("dup2(/dev/null, STDIN) failed: %m"); | |
2082 (void) close(new_fd); | |
2083 } | |
2084 if (dup2(0, 1) < 0) /* stdout -> /dev/null */ | |
2085 error("dup2(/dev/null, STDOUT) failed: %m"); | |
2086 if (dup2(0, 2) < 0) /* stderr -> /dev/null */ | |
2087 error("dup2(/dev/null, STDERR) failed: %m"); | |
2088 } | |
2089 | |
2090 #ifdef BSD | |
2091 /* Force the priority back to zero if pppd is running higher. */ | |
2092 if (setpriority (PRIO_PROCESS, 0, 0) < 0) | |
2093 warn("can't reset priority to 0: %m"); | |
2094 #endif | |
2095 | |
2096 /* SysV recommends a second fork at this point. */ | |
2097 | |
2098 /* run the program */ | |
2099 (void) execve(prog, args, script_env); | |
2100 if (must_exist || errno != ENOENT) { | |
2101 /* have to reopen the log, there's nowhere else | |
2102 for the message to go. */ | |
2103 reopen_log(); | |
2104 syslog(LOG_ERR, "Can't execute %s: %m", prog); | |
2105 closelog(); | |
2106 } | |
2107 _exit(-1); | |
2108 } | |
2109 | |
2110 if (debug) | |
2111 dbglog("Script %s started (pid %d)", prog, pid); | |
2112 record_child(pid, prog, done, arg); | |
2113 | |
2114 return (pid); | |
2115 } | |
2116 | |
2117 | |
2118 /* | |
2119 * record_child - add a child process to the list for reap_kids | |
2120 * to use. | |
2121 */ | |
2122 static void | |
2123 record_child(pid, prog, done, arg) | |
2124 pid_t pid; | |
2125 char *prog; | |
2126 void (*done) __P((void *, int)); | |
2127 void *arg; | |
2128 { | |
2129 struct subprocess *chp; | |
2130 | |
2131 ++n_children; | |
2132 | |
2133 chp = (struct subprocess *) malloc(sizeof(struct subprocess)); | |
2134 if (chp == NULL) { | |
2135 warn("losing track of %s process", prog); | |
2136 } else { | |
2137 chp->pid = pid; | |
2138 chp->prog = prog; | |
2139 chp->done = done; | |
2140 chp->arg = arg; | |
2141 chp->next = children; | |
2142 children = chp; | |
2143 } | |
2144 } | |
2145 | |
2146 | |
2147 /* | |
2148 * reap_kids - get status from any dead child processes, | |
2149 * and log a message for abnormal terminations. | |
2150 */ | |
2151 static int | |
2152 reap_kids(waitfor) | |
2153 int waitfor; | |
2154 { | |
2155 pid_t pid; | |
2156 int status, i; | |
2157 struct subprocess *chp, **prevp; | |
2158 | |
2159 got_sigchld = 0; | |
2160 if (n_children == 0) | |
2161 return (0); | |
2162 | |
2163 /*CONSTANTCONDITION*/ | |
2164 while (1) { | |
2165 pid = waitpid(-1, &status, (waitfor ? 0 : WNOHANG)); | |
2166 if (pid == 0) { | |
2167 break; /* return 0 */ | |
2168 } else if (pid == -1) { | |
2169 if (errno == EINTR) | |
2170 continue; | |
2171 if (errno != ECHILD) | |
2172 error("Error waiting for child process: %m"); | |
2173 return (-1); | |
2174 } else { | |
2175 for (prevp = &children; (chp = *prevp) != NULL; | |
2176 prevp = &chp->next) { | |
2177 if (chp->pid == pid) { | |
2178 --n_children; | |
2179 *prevp = chp->next; | |
2180 break; | |
2181 } | |
2182 } | |
2183 if (WIFSIGNALED(status) || WIFSTOPPED(status)) { | |
2184 i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); | |
2185 warn("Child process %s (pid %d) %s with signal %d (%s)", | |
2186 (chp != NULL ? chp->prog : "??"), pid, | |
2187 (WIFSIGNALED(status) ? "terminated" : "stopped"), | |
2188 i, signal_name(i)); | |
2189 } else if (debug) { | |
2190 dbglog("Child process %s finished (pid %d), status = %d", | |
2191 (chp != NULL ? chp->prog: "??"), pid, | |
2192 WEXITSTATUS(status)); | |
2193 } | |
2194 if ((chp != NULL) && (chp->done != NULL)) | |
2195 (*chp->done)(chp->arg, status); | |
2196 if (chp != NULL) | |
2197 free(chp); | |
2198 } | |
2199 } | |
2200 return (0); | |
2201 } | |
2202 | |
2203 /* | |
2204 * infanticide - timeout while waiting for child process. | |
2205 */ | |
2206 /*ARGSUSED*/ | |
2207 static void | |
2208 infanticide(sig) | |
2209 int sig; | |
2210 { | |
2211 struct subprocess *chp; | |
2212 static int runcount = 0; | |
2213 | |
2214 if (runcount < 2) { | |
2215 for (chp = children; chp != NULL; chp = chp->next) | |
2216 (void) kill(chp->pid, runcount == 0 ? SIGTERM : SIGKILL); | |
2217 } else { | |
2218 kill_my_pg(SIGTERM); | |
2219 /* Quit and hope for the best. */ | |
2220 n_children = 0; | |
2221 } | |
2222 runcount++; | |
2223 } | |
2224 | |
2225 /* | |
2226 * Perform final wait before exiting. | |
2227 */ | |
2228 static void | |
2229 final_reap() | |
2230 { | |
2231 struct sigaction sa; | |
2232 struct subprocess *chp; | |
2233 | |
2234 if (n_children > 0 && debug) { | |
2235 dbglog("Waiting for %d child processes...", n_children); | |
2236 for (chp = children; chp != NULL; chp = chp->next) | |
2237 dbglog(" pid %d: %s", chp->pid, chp->prog); | |
2238 } | |
2239 BZERO(&sa, sizeof (sa)); | |
2240 /*CONSTANTCONDITION*/ SIGNAL(SIGALRM, infanticide); | |
2241 while (n_children > 0) { | |
2242 (void) alarm(7); | |
2243 if (reap_kids(1) < 0) | |
2244 break; | |
2245 } | |
2246 (void) alarm(0); | |
2247 } | |
2248 | |
2249 /* | |
2250 * novm - log an error message saying we ran out of memory, and die. | |
2251 */ | |
2252 void | |
2253 novm(msg) | |
2254 char *msg; | |
2255 { | |
2256 fatal("Virtual memory exhausted allocating %s\n", msg); | |
2257 } | |
2258 | |
2259 /* | |
2260 * script_setenv - set an environment variable value to be used | |
2261 * for scripts that we run (e.g. ip-up, auth-up, etc.) | |
2262 */ | |
2263 void | |
2264 script_setenv(var, value, iskey) | |
2265 const char *var; | |
2266 const char *value; | |
2267 int iskey; | |
2268 { | |
2269 size_t varl = strlen(var); | |
2270 size_t vl = varl + strlen(value) + 2; | |
2271 int i; | |
2272 char *p, *newstring; | |
2273 | |
2274 /* | |
2275 * XXX: Can we assert that a tdb write lock is held here ? It appears that | |
2276 * Linux's use of tdb is not safe. | |
2277 */ | |
2278 newstring = (char *) malloc(vl+1); | |
2279 if (newstring == NULL) { | |
2280 novm("script environment string"); | |
2281 return; | |
2282 } | |
2283 *newstring++ = iskey; | |
2284 (void) slprintf(newstring, vl, "%s=%s", var, value); | |
2285 | |
2286 /* check if this variable is already set */ | |
2287 if (script_env != NULL) { | |
2288 for (i = 0; (p = script_env[i]) != NULL; ++i) { | |
2289 if (strncmp(p, var, varl) == 0 && p[varl] == '=') { | |
2290 #ifdef HAVE_MULTILINK | |
2291 if (p[-1] != '\0' && pppdb != NULL) | |
2292 delete_db_key(p); | |
2293 #endif | |
2294 free(p-1); | |
2295 script_env[i] = newstring; | |
2296 #ifdef HAVE_MULTILINK | |
2297 if (iskey && pppdb != NULL) | |
2298 add_db_key(newstring); | |
2299 update_db_entry(); | |
2300 #endif | |
2301 return; | |
2302 } | |
2303 } | |
2304 } else { | |
2305 /* no space allocated for script env. ptrs. yet */ | |
2306 i = 0; | |
2307 script_env = (char **) malloc(16 * sizeof(char *)); | |
2308 if (script_env == NULL) { | |
2309 novm("script environment variable."); | |
2310 return; | |
2311 } | |
2312 s_env_nalloc = 16; | |
2313 } | |
2314 | |
2315 /* reallocate script_env with more space if needed */ | |
2316 if (i + 1 >= s_env_nalloc) { | |
2317 int new_n = i + 17; | |
2318 char **newenv = (char **) realloc((void *)script_env, | |
2319 new_n * sizeof(char *)); | |
2320 if (newenv == NULL) { | |
2321 novm("expanded script environment variable."); | |
2322 return; | |
2323 } | |
2324 script_env = newenv; | |
2325 s_env_nalloc = new_n; | |
2326 } | |
2327 | |
2328 script_env[i] = newstring; | |
2329 script_env[i+1] = NULL; | |
2330 | |
2331 #ifdef HAVE_MULTILINK | |
2332 if (pppdb != NULL) { | |
2333 if (iskey) | |
2334 add_db_key(newstring); | |
2335 update_db_entry(); | |
2336 } | |
2337 #endif | |
2338 } | |
2339 | |
2340 /* | |
2341 * script_unsetenv - remove a variable from the environment | |
2342 * for scripts. | |
2343 */ | |
2344 void | |
2345 script_unsetenv(var) | |
2346 const char *var; | |
2347 { | |
2348 int vl = strlen(var); | |
2349 int i; | |
2350 char *p; | |
2351 | |
2352 /* | |
2353 * XXX: Can we assert that a tdb write lock is held here ? It appears that | |
2354 * Linux's use of tdb is not safe. | |
2355 */ | |
2356 if (script_env == NULL) | |
2357 return; | |
2358 for (i = 0; (p = script_env[i]) != NULL; ++i) { | |
2359 if (strncmp(p, var, vl) == 0 && p[vl] == '=') { | |
2360 #ifdef HAVE_MULTILINK | |
2361 if (p[-1] != '\0' && pppdb != NULL) | |
2362 delete_db_key(p); | |
2363 #endif | |
2364 free(p-1); | |
2365 while ((script_env[i] = script_env[i+1]) != NULL) | |
2366 ++i; | |
2367 break; | |
2368 } | |
2369 } | |
2370 #ifdef HAVE_MULTILINK | |
2371 if ((pppdb != NULL) && (p != NULL)) | |
2372 update_db_entry(); | |
2373 #endif | |
2374 } | |
2375 | |
2376 /* | |
2377 * script_getenv - find a variable in the script environment. | |
2378 */ | |
2379 const char * | |
2380 script_getenv(var) | |
2381 const char *var; | |
2382 { | |
2383 int vl = strlen(var); | |
2384 int i; | |
2385 char *p; | |
2386 | |
2387 if (script_env == NULL) | |
2388 return (NULL); | |
2389 for (i = 0; (p = script_env[i]) != NULL; ++i) { | |
2390 if (strncmp(p, var, vl) == 0 && p[vl] == '=') | |
2391 return ((const char *)p+vl+1); | |
2392 } | |
2393 return (NULL); | |
2394 } | |
2395 | |
2396 #ifdef HAVE_MULTILINK | |
2397 /* | |
2398 * update_db_entry - update our entry in the database. | |
2399 */ | |
2400 static void | |
2401 update_db_entry() | |
2402 { | |
2403 TDB_DATA key, dbuf; | |
2404 int vlen, i; | |
2405 char *p, *q, *vbuf; | |
2406 | |
2407 if (script_env == NULL) | |
2408 return; | |
2409 /* | |
2410 * vlen needs to be initialized as 1, or otherwise, the last string | |
2411 * is truncated by slprintf. | |
2412 */ | |
2413 vlen = 1; | |
2414 for (i = 0; (p = script_env[i]) != NULL; ++i) | |
2415 vlen += strlen(p) + 1; | |
2416 vbuf = malloc(vlen); | |
2417 if (vbuf == NULL) | |
2418 novm("database entry"); | |
2419 q = vbuf; | |
2420 for (i = 0; (p = script_env[i]) != NULL; ++i) | |
2421 q += slprintf(q, vbuf + vlen - q, "%s;", p); | |
2422 | |
2423 key.dptr = db_key; | |
2424 key.dsize = strlen(db_key); | |
2425 dbuf.dptr = vbuf; | |
2426 dbuf.dsize = vlen; | |
2427 if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) | |
2428 error("tdb_store failed: %s", tdb_error(pppdb)); | |
2429 } | |
2430 | |
2431 /* | |
2432 * add_db_key - add a key that we can use to look up our database entry. | |
2433 */ | |
2434 static void | |
2435 add_db_key(str) | |
2436 const char *str; | |
2437 { | |
2438 TDB_DATA key, dbuf; | |
2439 | |
2440 key.dptr = (char *) str; | |
2441 key.dsize = strlen(str); | |
2442 dbuf.dptr = db_key; | |
2443 dbuf.dsize = strlen(db_key); | |
2444 if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) | |
2445 error("tdb_store key failed: %s", tdb_error(pppdb)); | |
2446 } | |
2447 | |
2448 /* | |
2449 * delete_db_key - delete a key for looking up our database entry. | |
2450 */ | |
2451 static void | |
2452 delete_db_key(str) | |
2453 const char *str; | |
2454 { | |
2455 TDB_DATA key; | |
2456 | |
2457 key.dptr = (char *) str; | |
2458 key.dsize = strlen(str); | |
2459 (void) tdb_delete(pppdb, key); | |
2460 } | |
2461 | |
2462 /* | |
2463 * cleanup_db - delete all the entries we put in the database. | |
2464 */ | |
2465 static void | |
2466 cleanup_db() | |
2467 { | |
2468 TDB_DATA key; | |
2469 int i; | |
2470 char *p; | |
2471 | |
2472 key.dptr = db_key; | |
2473 key.dsize = strlen(db_key); | |
2474 (void) tdb_delete(pppdb, key); | |
2475 for (i = 0; (p = script_env[i]) != NULL; ++i) | |
2476 if (p[-1] != '\0') | |
2477 delete_db_key(p); | |
2478 } | |
2479 #endif /* HAVE_MULTILINK */ | |
2480 | |
2481 /* | |
2482 * open_socket - establish a stream socket connection to the nominated | |
2483 * host and port. | |
2484 * XXX: Need IPv6 support for those systems that support it (use getaddrinfo), | |
2485 * but requires portability changes. | |
2486 */ | |
2487 static int | |
2488 open_socket(dest) | |
2489 char *dest; | |
2490 { | |
2491 char *sep, *endp = NULL; | |
2492 int sock; | |
2493 int port = -1; | |
2494 u_int32_t host; | |
2495 struct hostent *hent = NULL; | |
2496 struct sockaddr_in sad; | |
2497 struct servent *se; | |
2498 | |
2499 /* parse host:port and resolve host to an IP address */ | |
2500 sep = strchr(dest, ':'); | |
2501 if (sep != NULL) { | |
2502 se = getservbyname((const char *)sep+1, "tcp"); | |
2503 if (se != NULL) { | |
2504 port = ntohs(se->s_port); | |
2505 } else { | |
2506 port = strtol(sep+1, &endp, 10); | |
2507 if (endp == sep+1 || *endp != '\0') { | |
2508 error("Can't parse host:port for socket destination"); | |
2509 return (-1); | |
2510 } | |
2511 } | |
2512 } | |
2513 if (port < 0 || port > 65535 || sep == dest) { | |
2514 error("Can't parse host:port for socket destination"); | |
2515 return (-1); | |
2516 } | |
2517 *sep = '\0'; | |
2518 host = inet_addr(dest); | |
2519 if (host == (u_int32_t) -1) { | |
2520 hent = gethostbyname(dest); | |
2521 if (hent == NULL) { | |
2522 error("%s: unknown host in socket option", dest); | |
2523 *sep = ':'; | |
2524 return (-1); | |
2525 } | |
2526 BCOPY(hent->h_addr_list[0], &host, sizeof(host)); | |
2527 hent->h_addr_list++; | |
2528 } | |
2529 *sep = ':'; | |
2530 | |
2531 for (;;) { | |
2532 /* get a socket and connect it to the other end */ | |
2533 sock = socket(PF_INET, SOCK_STREAM, 0); | |
2534 if (sock < 0) { | |
2535 error("Can't create socket: %m"); | |
2536 return (-1); | |
2537 } | |
2538 BZERO(&sad, sizeof(sad)); | |
2539 sad.sin_family = AF_INET; | |
2540 sad.sin_port = htons(port); | |
2541 sad.sin_addr.s_addr = host; | |
2542 if (connect(sock, (struct sockaddr *)&sad, sizeof(sad)) >= 0) { | |
2543 break; /* return sock file descriptor */ | |
2544 } | |
2545 if ((hent != NULL) && (hent->h_addr_list != NULL)) { | |
2546 BCOPY(hent->h_addr_list[0], &host, sizeof(host)); | |
2547 hent->h_addr_list++; | |
2548 (void) close(sock); | |
2549 continue; | |
2550 } | |
2551 error("Can't connect to %s: %m", dest); | |
2552 (void) close(sock); | |
2553 return (-1); | |
2554 } | |
2555 return (sock); | |
2556 } | |
2557 | |
2558 /* | |
2559 * print_ncpstate - prints out current NCP state. | |
2560 * | |
2561 * We're normally called from SIGUSR1 here, but this is safe because | |
2562 * these signals are blocked unless we're idle waiting for events. | |
2563 * There's no need to otherwise lock the data structures referenced. | |
2564 */ | |
2565 void | |
2566 print_ncpstate(unit, strptr) | |
2567 int unit; | |
2568 FILE *strptr; | |
2569 { | |
2570 struct protent *protp; | |
2571 int i; | |
2572 | |
2573 (void) flprintf(strptr, "In %s phase\n", phase_name(phase)); | |
2574 for (i = 0; (protp = protocols[i]) != NULL; ++i) { | |
2575 if (protp->print_stat != NULL) | |
2576 (*protp->print_stat)(unit, strptr); | |
2577 } | |
2578 sys_print_state(strptr); | |
2579 } | |
2580 | |
2581 /* | |
2582 * start_charshunt - create a child process to run the character shunt. | |
2583 */ | |
2584 static int | |
2585 start_charshunt(ifd, ofd) | |
2586 int ifd, ofd; | |
2587 { | |
2588 pid_t cpid; | |
2589 | |
2590 cpid = fork(); | |
2591 if (cpid == (pid_t)-1) { | |
2592 error("Can't fork process for character shunt: %m"); | |
2593 return (0); | |
2594 } | |
2595 if (cpid == (pid_t)0) { | |
2596 /* child */ | |
2597 (void) close(pty_slave); | |
2598 pty_slave = -1; | |
2599 (void) setgid(getgid()); | |
2600 (void) setuid(uid); | |
2601 if (getuid() != uid) | |
2602 fatal("setuid failed"); | |
2603 if (!nodetach) | |
2604 log_to_fd = -1; | |
2605 charshunt(ifd, ofd, record_file); | |
2606 exit(0); | |
2607 } | |
2608 charshunt_pid = cpid; | |
2609 (void) close(pty_master); | |
2610 pty_master = -1; | |
2611 ttyfd = pty_slave; | |
2612 record_child(cpid, "pppd (charshunt)", charshunt_done, NULL); | |
2613 return (1); | |
2614 } | |
2615 | |
2616 /*ARGSUSED*/ | |
2617 static void | |
2618 charshunt_done(arg, status) | |
2619 void *arg; | |
2620 int status; | |
2621 { | |
2622 charshunt_pid = (pid_t)0; | |
2623 } | |
2624 | |
2625 static void | |
2626 reportme(int signo) | |
2627 { | |
2628 dbglog("charshunt taking signal %d", signo); | |
2629 exit(1); | |
2630 } | |
2631 | |
2632 /* | |
2633 * charshunt - the character shunt, which passes characters between | |
2634 * the pty master side and the serial port (or stdin/stdout). | |
2635 * This runs as the user (not as root). | |
2636 * (We assume ofd >= ifd which is true the way this gets called. :-). | |
2637 */ | |
2638 static void | |
2639 charshunt(ifd, ofd, record_file) | |
2640 int ifd, ofd; | |
2641 char *record_file; | |
2642 { | |
2643 int n, nfds; | |
2644 fd_set ready, writey; | |
2645 u_char *ibufp, *obufp; | |
2646 int nibuf, nobuf; | |
2647 int flags; | |
2648 struct timeval lasttime; | |
2649 FILE *recordf = NULL; | |
2650 int ilevel, olevel, max_level; | |
2651 struct timeval levelt, tout, *top; | |
2652 | |
2653 /* | |
2654 * Reset signal handlers. | |
2655 */ | |
2656 (void) signal(SIGHUP, SIG_IGN); /* Hangup */ | |
2657 (void) signal(SIGINT, reportme); /* Interrupt */ | |
2658 (void) signal(SIGTERM, reportme); /* Terminate */ | |
2659 (void) signal(SIGCHLD, reportme); | |
2660 (void) signal(SIGUSR1, reportme); | |
2661 (void) signal(SIGUSR2, reportme); | |
2662 (void) signal(SIGABRT, reportme); | |
2663 (void) signal(SIGALRM, reportme); | |
2664 (void) signal(SIGFPE, reportme); | |
2665 (void) signal(SIGILL, reportme); | |
2666 (void) signal(SIGPIPE, reportme); | |
2667 (void) signal(SIGQUIT, reportme); | |
2668 #ifndef DEBUG | |
2669 (void) signal(SIGSEGV, reportme); | |
2670 #endif | |
2671 #ifdef SIGBUS | |
2672 (void) signal(SIGBUS, reportme); | |
2673 #endif | |
2674 #ifdef SIGEMT | |
2675 (void) signal(SIGEMT, reportme); | |
2676 #endif | |
2677 #ifdef SIGPOLL | |
2678 (void) signal(SIGPOLL, reportme); | |
2679 #endif | |
2680 #ifdef SIGPROF | |
2681 (void) signal(SIGPROF, reportme); | |
2682 #endif | |
2683 #ifdef SIGSYS | |
2684 (void) signal(SIGSYS, reportme); | |
2685 #endif | |
2686 #ifdef SIGTRAP | |
2687 (void) signal(SIGTRAP, reportme); | |
2688 #endif | |
2689 #ifdef SIGVTALRM | |
2690 (void) signal(SIGVTALRM, reportme); | |
2691 #endif | |
2692 #ifdef SIGXCPU | |
2693 (void) signal(SIGXCPU, reportme); | |
2694 #endif | |
2695 #ifdef SIGXFSZ | |
2696 (void) signal(SIGXFSZ, reportme); | |
2697 #endif | |
2698 | |
2699 /* | |
2700 * Open the record file if required. | |
2701 */ | |
2702 if (record_file != NULL) { | |
2703 recordf = fopen(record_file, "a"); | |
2704 if (recordf == NULL) | |
2705 error("Couldn't create record file %s: %m", record_file); | |
2706 } | |
2707 | |
2708 /* set all the fds to non-blocking mode */ | |
2709 flags = fcntl(pty_master, F_GETFL); | |
2710 if (flags == -1 | |
2711 || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1) | |
2712 warn("couldn't set pty master to nonblock: %m"); | |
2713 flags = fcntl(ifd, F_GETFL); | |
2714 if (flags == -1 | |
2715 || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1) | |
2716 warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty")); | |
2717 if (ofd != ifd) { | |
2718 flags = fcntl(ofd, F_GETFL); | |
2719 if (flags == -1 | |
2720 || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1) | |
2721 warn("couldn't set stdout to nonblock: %m"); | |
2722 } | |
2723 | |
2724 nibuf = nobuf = 0; | |
2725 ibufp = obufp = NULL; | |
2726 | |
2727 ilevel = olevel = 0; | |
2728 (void) gettimeofday(&levelt, NULL); | |
2729 if (max_data_rate) { | |
2730 max_level = max_data_rate / 10; | |
2731 if (max_level < MAXLEVELMINSIZE) | |
2732 max_level = MAXLEVELMINSIZE; | |
2733 } else | |
2734 max_level = sizeof(inpacket_buf) + 1; | |
2735 | |
2736 nfds = (ofd > pty_master? ofd: pty_master) + 1; | |
2737 if (recordf != NULL) { | |
2738 (void) gettimeofday(&lasttime, NULL); | |
2739 (void) putc(RECMARK_TIMESTART, recordf); /* put start marker */ | |
2740 (void) putc(lasttime.tv_sec >> 24, recordf); | |
2741 (void) putc(lasttime.tv_sec >> 16, recordf); | |
2742 (void) putc(lasttime.tv_sec >> 8, recordf); | |
2743 (void) putc(lasttime.tv_sec, recordf); | |
2744 lasttime.tv_usec = 0; | |
2745 } | |
2746 | |
2747 while (nibuf != 0 || nobuf != 0 || ofd >= 0 || pty_master >= 0) { | |
2748 top = 0; | |
2749 tout.tv_sec = 0; | |
2750 tout.tv_usec = 10000; | |
2751 FD_ZERO(&ready); | |
2752 FD_ZERO(&writey); | |
2753 if (nibuf != 0) { | |
2754 if (ilevel >= max_level) | |
2755 top = &tout; | |
2756 else if (pty_master >= 0) | |
2757 FD_SET(pty_master, &writey); | |
2758 } else if (ifd >= 0) | |
2759 FD_SET(ifd, &ready); | |
2760 if (nobuf != 0) { | |
2761 if (olevel >= max_level) | |
2762 top = &tout; | |
2763 else if (ofd >= 0) | |
2764 FD_SET(ofd, &writey); | |
2765 } else { | |
2766 /* Don't read from pty if it's gone or it has closed. */ | |
2767 if (pty_master >= 0 && ofd >= 0) | |
2768 FD_SET(pty_master, &ready); | |
2769 } | |
2770 if (select(nfds, &ready, &writey, NULL, top) < 0) { | |
2771 if (errno != EINTR) | |
2772 fatal("select"); | |
2773 continue; | |
2774 } | |
2775 if (max_data_rate) { | |
2776 double dt; | |
2777 int nbt; | |
2778 struct timeval now; | |
2779 | |
2780 (void) gettimeofday(&now, NULL); | |
2781 dt = (now.tv_sec - levelt.tv_sec | |
2782 + (now.tv_usec - levelt.tv_usec) / 1e6); | |
2783 nbt = (int)(dt * max_data_rate); | |
2784 ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt; | |
2785 olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt; | |
2786 levelt = now; | |
2787 } else | |
2788 ilevel = olevel = 0; | |
2789 if (FD_ISSET(ifd, &ready)) { | |
2790 ibufp = inpacket_buf; | |
2791 nibuf = read(ifd, ibufp, sizeof(inpacket_buf)); | |
2792 if (nibuf < 0 && errno == EIO) | |
2793 nibuf = 0; | |
2794 if (nibuf < 0 || pty_master == -1) { | |
2795 if (errno != EINTR && errno != EAGAIN) { | |
2796 error("Error reading standard input: %m"); | |
2797 break; | |
2798 } | |
2799 nibuf = 0; | |
2800 } else if (nibuf == 0) { | |
2801 /* end of file from stdin */ | |
2802 (void) close(pty_master); | |
2803 pty_master = -1; | |
2804 (void) close(ifd); | |
2805 ifd = -1; | |
2806 if (recordf) | |
2807 if (!record_write(recordf, RECMARK_ENDRECV, NULL, 0, | |
2808 &lasttime)) | |
2809 recordf = NULL; | |
2810 } else { | |
2811 FD_SET(pty_master, &writey); | |
2812 if (recordf) | |
2813 if (!record_write(recordf, RECMARK_STARTRECV, ibufp, nibuf, | |
2814 &lasttime)) | |
2815 recordf = NULL; | |
2816 } | |
2817 } | |
2818 if (ofd >= 0 && pty_master >= 0 && FD_ISSET(pty_master, &ready)) { | |
2819 obufp = outpacket_buf; | |
2820 nobuf = read(pty_master, obufp, sizeof(outpacket_buf)); | |
2821 if (nobuf < 0 && errno == EIO) | |
2822 nobuf = 0; | |
2823 if (nobuf < 0 || ofd == -1) { | |
2824 if (!(errno == EINTR || errno == EAGAIN)) { | |
2825 error("Error reading pseudo-tty master: %m"); | |
2826 break; | |
2827 } | |
2828 nobuf = 0; | |
2829 } else if (nobuf == 0) { | |
2830 /* end of file from the pty - slave side has closed */ | |
2831 nibuf = 0; | |
2832 (void) close(ofd); | |
2833 ofd = -1; | |
2834 if (recordf) | |
2835 if (!record_write(recordf, RECMARK_ENDSEND, NULL, 0, | |
2836 &lasttime)) | |
2837 recordf = NULL; | |
2838 } else { | |
2839 FD_SET(ofd, &writey); | |
2840 if (recordf) | |
2841 if (!record_write(recordf, RECMARK_STARTSEND, obufp, nobuf, | |
2842 &lasttime)) | |
2843 recordf = NULL; | |
2844 } | |
2845 } | |
2846 if (ofd == -1) | |
2847 nobuf = 0; | |
2848 else if (FD_ISSET(ofd, &writey)) { | |
2849 n = nobuf; | |
2850 if (olevel + n > max_level) | |
2851 n = max_level - olevel; | |
2852 n = write(ofd, obufp, n); | |
2853 if (n < 0) { | |
2854 if (errno == EIO) { | |
2855 (void) close(ofd); | |
2856 ofd = -1; | |
2857 nobuf = 0; | |
2858 } else if (errno != EAGAIN && errno != EINTR) { | |
2859 error("Error writing standard output: %m"); | |
2860 break; | |
2861 } | |
2862 } else { | |
2863 obufp += n; | |
2864 nobuf -= n; | |
2865 olevel += n; | |
2866 } | |
2867 } | |
2868 if (pty_master == -1) | |
2869 nibuf = 0; | |
2870 else if (FD_ISSET(pty_master, &writey)) { | |
2871 n = nibuf; | |
2872 if (ilevel + n > max_level) | |
2873 n = max_level - ilevel; | |
2874 n = write(pty_master, ibufp, n); | |
2875 if (n < 0) { | |
2876 if (errno == EAGAIN || errno == EINTR) | |
2877 continue; | |
2878 if (errno != EIO) { | |
2879 error("Error writing pseudo-tty master: %m"); | |
2880 break; | |
2881 } | |
2882 (void) close(pty_master); | |
2883 pty_master = -1; | |
2884 nibuf = 0; | |
2885 } else { | |
2886 ibufp += n; | |
2887 nibuf -= n; | |
2888 ilevel += n; | |
2889 } | |
2890 } | |
2891 } | |
2892 exit(0); | |
2893 } | |
2894 | |
2895 static int | |
2896 record_write(f, code, buf, nb, tp) | |
2897 FILE *f; | |
2898 int code; | |
2899 u_char *buf; | |
2900 int nb; | |
2901 struct timeval *tp; | |
2902 { | |
2903 struct timeval now; | |
2904 int diff; | |
2905 | |
2906 (void) gettimeofday(&now, NULL); | |
2907 now.tv_usec /= 100000; /* actually 1/10 s, not usec now */ | |
2908 diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec); | |
2909 if (diff > 0) { | |
2910 if (diff > 255) { | |
2911 (void) putc(RECMARK_TIMEDELTA32, f); | |
2912 (void) putc(diff >> 24, f); | |
2913 (void) putc(diff >> 16, f); | |
2914 (void) putc(diff >> 8, f); | |
2915 (void) putc(diff, f); | |
2916 } else { | |
2917 (void) putc(RECMARK_TIMEDELTA8, f); | |
2918 (void) putc(diff, f); | |
2919 } | |
2920 *tp = now; | |
2921 } | |
2922 (void) putc(code, f); | |
2923 if (buf != NULL) { | |
2924 (void) putc(nb >> 8, f); | |
2925 (void) putc(nb, f); | |
2926 (void) fwrite(buf, nb, 1, f); | |
2927 } | |
2928 (void) fflush(f); | |
2929 if (ferror(f)) { | |
2930 error("Error writing record file: %m"); | |
2931 return (0); | |
2932 } | |
2933 return (1); | |
2934 } |