X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fmain.c;h=ee86eb8f35c0e84ec67b1d3f61be8a7b6d70a81d;hp=409628c4b0a03383d7647d32be1993851f7cce63;hb=6e6bb3246106e680463c106d1ee6b773fc4f9c5a;hpb=690865e93221a67d2ee33f4d184a8be79c3fc7ec diff --git a/pppd/main.c b/pppd/main.c index 409628c..ee86eb8 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -1,23 +1,72 @@ /* * main.c - Point-to-Point Protocol main module * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Copyright (c) 1999-2004 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: main.c,v 1.117 2002/10/27 12:04:07 fcusack Exp $" +#define RCSID "$Id: main.c,v 1.142 2004/11/04 10:05:23 paulus Exp $" #include #include @@ -51,7 +100,8 @@ #include "ipv6cp.h" #endif #include "upap.h" -#include "chap.h" +#include "chap-new.h" +#include "eap.h" #include "ccp.h" #include "ecp.h" #include "pathnames.h" @@ -89,6 +139,7 @@ struct notifier *pidchange = NULL; struct notifier *phasechange = NULL; struct notifier *exitnotify = NULL; struct notifier *sigreceived = NULL; +struct notifier *fork_notifier = NULL; int hungup; /* terminal has been hung up */ int privileged; /* we're running as real uid root */ @@ -100,6 +151,8 @@ int do_callback; /* != 0 if we should do callback next */ int doing_callback; /* != 0 if we are doing callback */ int ppp_session_number; /* Session number, for channels with such a concept (eg PPPoE) */ +int childwait_done; /* have timed out waiting for children */ + #ifdef USE_TDB TDB_CONTEXT *pppdb; /* database for storing status etc. */ #endif @@ -115,6 +168,7 @@ static int conn_running; /* we have a [dis]connector running */ static int devfd; /* fd of underlying device */ static int fd_ppp = -1; /* fd for talking PPP */ static int fd_loop; /* fd for getting demand-dial packets */ +static int fd_devnull; /* fd for /dev/null */ int phase; /* where the link is at */ int kill_link; @@ -124,6 +178,7 @@ int got_sigusr2; int got_sigterm; int got_sighup; +static sigset_t signals_handled; static int waiting; static sigjmp_buf sigjmp; @@ -145,10 +200,13 @@ int ngroups; /* How many groups valid in groups */ static struct timeval start_time; /* Time when link was started. */ +static struct pppd_stats old_link_stats; struct pppd_stats link_stats; -int link_connect_time; +unsigned link_connect_time; int link_stats_valid; +int error_count; + /* * We maintain a list of child process pids and * functions to call when they exit. @@ -166,8 +224,8 @@ static struct subprocess *children; /* Prototypes for procedures local to this file. */ static void setup_signals __P((void)); -static void create_pidfile __P((void)); -static void create_linkpidfile __P((void)); +static void create_pidfile __P((int pid)); +static void create_linkpidfile __P((int pid)); static void cleanup __P((void)); static void get_input __P((void)); static void calltimeout __P((void)); @@ -180,7 +238,8 @@ static void toggle_debug __P((int)); static void open_ccp __P((int)); static void bad_signal __P((int)); static void holdoff_end __P((void *)); -static int reap_kids __P((int waitfor)); +static int reap_kids __P((void)); +static void childwait_end __P((void *)); #ifdef USE_TDB static void update_db_entry __P((void)); @@ -190,7 +249,7 @@ static void cleanup_db __P((void)); #endif static void handle_events __P((void)); -static void print_link_stats __P((void)); +void print_link_stats __P((void)); extern char *ttyname __P((int)); extern char *getlogin __P((void)); @@ -229,6 +288,7 @@ struct protent *protocols[] = { #ifdef AT_CHANGE &atcp_protent, #endif + &eap_protent, NULL }; @@ -253,18 +313,6 @@ main(argc, argv) link_stats_valid = 0; new_phase(PHASE_INITIALIZE); - /* - * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else. - * This way we can close 0, 1, 2 in detach() without clobbering - * a fd that we are using. - */ - if ((i = open("/dev/null", O_RDWR)) >= 0) { - while (0 <= i && i <= 2) - i = dup(i); - if (i >= 0) - close(i); - } - script_env = NULL; /* Initialize syslog facilities */ @@ -362,14 +410,6 @@ main(argc, argv) end_pr_log(); } - /* - * Early check for remote number authorization. - */ - if (!auth_number()) { - warn("calling number %q is not authorized", remote_number); - exit(EXIT_CNID_AUTH_FAILED); - } - if (dryrun) die(0); @@ -378,6 +418,17 @@ main(argc, argv) */ sys_init(); + /* Make sure fds 0, 1, 2 are open to somewhere. */ + fd_devnull = open(_PATH_DEVNULL, O_RDWR); + if (fd_devnull < 0) + fatal("Couldn't open %s: %m", _PATH_DEVNULL); + while (fd_devnull <= 2) { + i = dup(fd_devnull); + if (i < 0) + fatal("Critical shortage of file descriptors: dup failed: %m"); + fd_devnull = i; + } + #ifdef USE_TDB pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644); if (pppdb != NULL) { @@ -418,8 +469,6 @@ main(argc, argv) waiting = 0; - create_linkpidfile(); - /* * If we're doing dial-on-demand, set up the interface now. */ @@ -439,6 +488,7 @@ main(argc, argv) * Configure the interface and mark it up, etc. */ demand_conf(); + create_linkpidfile(getpid()); } do_callback = 0; @@ -495,6 +545,9 @@ main(argc, argv) status = EXIT_FATAL_ERROR; goto disconnect; } + /* create the pid file, now that we've obtained a ppp interface */ + if (!demand) + create_linkpidfile(getpid()); if (!demand && ifunit >= 0) set_ifunit(1); @@ -567,7 +620,8 @@ main(argc, argv) */ disconnect: new_phase(PHASE_DISCONNECT); - the_channel->disconnect(); + if (the_channel->disconnect) + the_channel->disconnect(); fail: if (the_channel->cleanup) @@ -602,16 +656,21 @@ main(argc, argv) } /* Wait for scripts to finish */ - /* XXX should have a timeout here */ - while (n_children > 0) { + reap_kids(); + if (n_children > 0) { + if (child_wait > 0) + TIMEOUT(childwait_end, NULL, child_wait); if (debug) { struct subprocess *chp; dbglog("Waiting for %d child processes...", n_children); for (chp = children; chp != NULL; chp = chp->next) dbglog(" script %s, pid %d", chp->prog, chp->pid); } - if (reap_kids(1) < 0) - break; + while (n_children > 0 && !childwait_done) { + handle_events(); + if (kill_link && !childwait_done) + childwait_end(NULL); + } } die(status); @@ -625,36 +684,37 @@ static void handle_events() { struct timeval timo; - sigset_t mask; kill_link = open_ccp_flag = 0; if (sigsetjmp(sigjmp, 1) == 0) { - sigprocmask(SIG_BLOCK, &mask, NULL); + sigprocmask(SIG_BLOCK, &signals_handled, NULL); if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) { - sigprocmask(SIG_UNBLOCK, &mask, NULL); + sigprocmask(SIG_UNBLOCK, &signals_handled, NULL); } else { waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); + sigprocmask(SIG_UNBLOCK, &signals_handled, NULL); wait_input(timeleft(&timo)); } } waiting = 0; calltimeout(); if (got_sighup) { + info("Hangup (SIGHUP)"); kill_link = 1; got_sighup = 0; if (status != EXIT_HANGUP) status = EXIT_USER_REQUEST; } if (got_sigterm) { + info("Terminating on signal %d", got_sigterm); kill_link = 1; persist = 0; status = EXIT_USER_REQUEST; got_sigterm = 0; } if (got_sigchld) { - reap_kids(0); /* Don't leave dead kids lying around */ got_sigchld = 0; + reap_kids(); /* Don't leave dead kids lying around */ } if (got_sigusr2) { open_ccp_flag = 1; @@ -669,19 +729,18 @@ static void setup_signals() { struct sigaction sa; - sigset_t mask; /* * Compute mask of all interesting signals and install signal handlers * for each. Only one signal handler may be active at a time. Therefore, * all other signals should be masked when any handler is executing. */ - sigemptyset(&mask); - sigaddset(&mask, SIGHUP); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTERM); - sigaddset(&mask, SIGCHLD); - sigaddset(&mask, SIGUSR2); + sigemptyset(&signals_handled); + sigaddset(&signals_handled, SIGHUP); + sigaddset(&signals_handled, SIGINT); + sigaddset(&signals_handled, SIGTERM); + sigaddset(&signals_handled, SIGCHLD); + sigaddset(&signals_handled, SIGUSR2); #define SIGNAL(s, handler) do { \ sa.sa_handler = handler; \ @@ -689,7 +748,7 @@ setup_signals() fatal("Couldn't establish signal handler (%d): %m", s); \ } while (0) - sa.sa_mask = mask; + sa.sa_mask = signals_handled; sa.sa_flags = 0; SIGNAL(SIGHUP, hup); /* Hangup */ SIGNAL(SIGINT, term); /* Interrupt */ @@ -758,8 +817,8 @@ set_ifunit(iskey) slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit); script_setenv("IFNAME", ifname, iskey); if (iskey) { - create_pidfile(); /* write pid to file */ - create_linkpidfile(); + create_pidfile(getpid()); /* write pid to file */ + create_linkpidfile(getpid()); } } @@ -771,9 +830,12 @@ detach() { int pid; char numbuf[16]; + int pipefd[2]; if (detached) return; + if (pipe(pipefd) == -1) + pipefd[0] = pipefd[1] = -1; if ((pid = fork()) < 0) { error("Couldn't detach (fork failed: %m)"); die(1); /* or just return? */ @@ -781,23 +843,28 @@ detach() if (pid != 0) { /* parent */ notify(pidchange, pid); + /* update pid files if they have been written already */ + if (pidfilename[0]) + create_pidfile(pid); + if (linkpidfile[0]) + create_linkpidfile(pid); exit(0); /* parent dies */ } setsid(); chdir("/"); - close(0); - close(1); - close(2); + dup2(fd_devnull, 0); + dup2(fd_devnull, 1); + dup2(fd_devnull, 2); detached = 1; if (log_default) log_to_fd = -1; - /* update pid files if they have been written already */ - if (pidfilename[0]) - create_pidfile(); - if (linkpidfile[0]) - create_linkpidfile(); slprintf(numbuf, sizeof(numbuf), "%d", getpid()); script_setenv("PPPD_PID", numbuf, 1); + + /* wait for parent to finish updating pid & lock files and die */ + close(pipefd[1]); + complete_read(pipefd[0], numbuf, 1); + close(pipefd[0]); } /* @@ -818,14 +885,15 @@ reopen_log() * Create a file containing our process ID. */ static void -create_pidfile() +create_pidfile(pid) + int pid; { FILE *pidfile; slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid", _PATH_VARRUN, ifname); if ((pidfile = fopen(pidfilename, "w")) != NULL) { - fprintf(pidfile, "%d\n", getpid()); + fprintf(pidfile, "%d\n", pid); (void) fclose(pidfile); } else { error("Failed to create pid file %s: %m", pidfilename); @@ -834,7 +902,8 @@ create_pidfile() } static void -create_linkpidfile() +create_linkpidfile(pid) + int pid; { FILE *pidfile; @@ -844,7 +913,7 @@ create_linkpidfile() slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid", _PATH_VARRUN, linkname); if ((pidfile = fopen(linkpidfile, "w")) != NULL) { - fprintf(pidfile, "%d\n", getpid()); + fprintf(pidfile, "%d\n", pid); if (ifname[0]) fprintf(pidfile, "%s\n", ifname); (void) fclose(pidfile); @@ -990,7 +1059,7 @@ get_input() * Toss all non-LCP packets unless LCP is OPEN. */ if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) { - MAINDEBUG(("get_input: Received non-LCP packet when LCP not open.")); + dbglog("Discarded non-LCP packet when LCP not open"); return; } @@ -1000,9 +1069,10 @@ get_input() */ if (phase <= PHASE_AUTHENTICATE && !(protocol == PPP_LCP || protocol == PPP_LQR - || protocol == PPP_PAP || protocol == PPP_CHAP)) { - MAINDEBUG(("get_input: discarding proto 0x%x in phase %d", - protocol, phase)); + || protocol == PPP_PAP || protocol == PPP_CHAP || + protocol == PPP_EAP)) { + dbglog("discarding proto 0x%x in phase %d", + protocol, phase); return; } @@ -1031,6 +1101,48 @@ get_input() lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); } +/* + * ppp_send_config - configure the transmit-side characteristics of + * the ppp interface. Returns -1, indicating an error, if the channel + * send_config procedure called error() (or incremented error_count + * itself), otherwise 0. + */ +int +ppp_send_config(unit, mtu, accm, pcomp, accomp) + int unit, mtu; + u_int32_t accm; + int pcomp, accomp; +{ + int errs; + + if (the_channel->send_config == NULL) + return 0; + errs = error_count; + (*the_channel->send_config)(mtu, accm, pcomp, accomp); + return (error_count != errs)? -1: 0; +} + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. Returns -1, indicating an error, if the channel + * recv_config procedure called error() (or incremented error_count + * itself), otherwise 0. + */ +int +ppp_recv_config(unit, mru, accm, pcomp, accomp) + int unit, mru; + u_int32_t accm; + int pcomp, accomp; +{ + int errs; + + if (the_channel->recv_config == NULL) + return 0; + errs = error_count; + (*the_channel->recv_config)(mru, accm, pcomp, accomp); + return (error_count != errs)? -1: 0; +} + /* * new_phase - signal the start of a new phase of pppd's operation. */ @@ -1051,7 +1163,7 @@ void die(status) int status; { - print_link_stats(); + print_link_stats(); cleanup(); notify(exitnotify, status); syslog(LOG_INFO, "Exit."); @@ -1097,9 +1209,22 @@ print_link_stats() info("Connect time %d.%d minutes.", t/10, t%10); info("Sent %u bytes, received %u bytes.", link_stats.bytes_out, link_stats.bytes_in); + link_stats_valid = 0; } } +/* + * reset_link_stats - "reset" stats when link goes up. + */ +void +reset_link_stats(u) + int u; +{ + if (!get_ppp_stats(u, &old_link_stats)) + return; + gettimeofday(&start_time, NULL); +} + /* * update_link_stats - get stats at link termination. */ @@ -1116,6 +1241,11 @@ update_link_stats(u) link_connect_time = now.tv_sec - start_time.tv_sec; link_stats_valid = 1; + link_stats.bytes_in -= old_link_stats.bytes_in; + link_stats.bytes_out -= old_link_stats.bytes_out; + link_stats.pkts_in -= old_link_stats.pkts_in; + link_stats.pkts_out -= old_link_stats.pkts_out; + slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time); script_setenv("CONNECT_TIME", numbuf, 0); slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out); @@ -1146,9 +1276,6 @@ timeout(func, arg, secs, usecs) { struct callout *newp, *p, **pp; - MAINDEBUG(("Timeout %p:%p in %d.%03d seconds.", func, arg, - secs, usecs/1000)); - /* * Allocate timeout. */ @@ -1187,8 +1314,6 @@ untimeout(func, arg) { struct callout **copp, *freep; - MAINDEBUG(("Untimeout %p:%p.", func, arg)); - /* * Find first matching timeout and remove it from the list. */ @@ -1253,6 +1378,7 @@ timeleft(tvp) /* * kill_my_pg - send a signal to our process group, and ignore it ourselves. + * We assume that sig is currently blocked. */ static void kill_my_pg(sig) @@ -1260,9 +1386,21 @@ kill_my_pg(sig) { struct sigaction act, oldact; + sigemptyset(&act.sa_mask); /* unnecessary in fact */ act.sa_handler = SIG_IGN; act.sa_flags = 0; kill(0, sig); + /* + * The kill() above made the signal pending for us, as well as + * the rest of our process group, but we don't want it delivered + * to us. It is blocked at the moment. Setting it to be ignored + * will cause the pending signal to be discarded. If we did the + * kill() after setting the signal to be ignored, it is unspecified + * (by POSIX) whether the signal is immediately discarded or left + * pending, and in fact Linux would leave it pending, and so it + * would be delivered after the current signal handler exits, + * leading to an infinite loop. + */ sigaction(sig, &act, &oldact); sigaction(sig, &oldact, NULL); } @@ -1279,7 +1417,7 @@ static void hup(sig) int sig; { - info("Hangup (SIGHUP)"); + /* can't log a message here, it can deadlock */ got_sighup = 1; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ @@ -1300,8 +1438,8 @@ static void term(sig) int sig; { - info("Terminating on signal %d.", sig); - got_sigterm = 1; + /* can't log a message here, it can deadlock */ + got_sigterm = sig; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ kill_my_pg(sig); @@ -1379,6 +1517,40 @@ bad_signal(sig) die(127); } +/* + * safe_fork - Create a child process. The child closes all the + * file descriptors that we don't want to leak to a script. + * The parent waits for the child to do this before returning. + */ +pid_t +safe_fork() +{ + pid_t pid; + int pipefd[2]; + char buf[1]; + + if (pipe(pipefd) == -1) + pipefd[0] = pipefd[1] = -1; + pid = fork(); + if (pid < 0) + return -1; + if (pid > 0) { + close(pipefd[1]); + /* this read() blocks until the close(pipefd[1]) below */ + complete_read(pipefd[0], buf, 1); + close(pipefd[0]); + return pid; + } + sys_close(); +#ifdef USE_TDB + tdb_close(pppdb); +#endif + notify(fork_notifier, 0); + close(pipefd[0]); + /* this close unblocks the read() call above in the parent */ + close(pipefd[1]); + return 0; +} /* * device_script - run a program to talk to the specified fds @@ -1391,12 +1563,13 @@ device_script(program, in, out, dont_wait) int in, out; int dont_wait; { - int pid, fd; + int pid; int status = -1; int errfd; + int fd; ++conn_running; - pid = fork(); + pid = safe_fork(); if (pid < 0) { --conn_running; @@ -1420,31 +1593,41 @@ device_script(program, in, out, dont_wait) } /* here we are executing in the child */ + /* make sure fds 0, 1, 2 are occupied */ while ((fd = dup(in)) >= 0) { - if (fd > 2) { + if (fd > 2) { close(fd); break; } } /* dup in and out to fds > 2 */ - in = dup(in); - out = dup(out); - if (log_to_fd >= 0) { - errfd = dup(log_to_fd); - } else { - errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); + { + int fd1 = in, fd2 = out, fd3 = log_to_fd; + + in = dup(in); + out = dup(out); + if (log_to_fd >= 0) { + errfd = dup(log_to_fd); + } else { + errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); + } + close(fd1); + close(fd2); + close(fd3); } /* close fds 0 - 2 and any others we can think of */ close(0); close(1); close(2); - sys_close(); if (the_channel->close) (*the_channel->close)(); + else + close(devfd); /* some plugins don't have a close function */ closelog(); + close(fd_devnull); /* dup the in, out, err fds to 0, 1, 2 */ dup2(in, 0); @@ -1504,66 +1687,54 @@ run_program(prog, args, must_exist, done, arg) return 0; } - pid = fork(); + pid = safe_fork(); if (pid == -1) { error("Failed to create child process for %s: %m", prog); return -1; } - if (pid == 0) { - int new_fd; + if (pid != 0) { + if (debug) + dbglog("Script %s started (pid %d)", prog, pid); + record_child(pid, prog, done, arg); + return pid; + } - /* Leave the current location */ - (void) setsid(); /* No controlling tty. */ - (void) umask (S_IRWXG|S_IRWXO); - (void) chdir ("/"); /* no current directory. */ - setuid(0); /* set real UID = root */ - setgid(getegid()); + /* Leave the current location */ + (void) setsid(); /* No controlling tty. */ + (void) umask (S_IRWXG|S_IRWXO); + (void) chdir ("/"); /* no current directory. */ + setuid(0); /* set real UID = root */ + setgid(getegid()); - /* Ensure that nothing of our device environment is inherited. */ - sys_close(); - closelog(); - close (0); - close (1); - close (2); - if (the_channel->close) - (*the_channel->close)(); - - /* Don't pass handles to the PPP device, even by accident. */ - new_fd = open (_PATH_DEVNULL, O_RDWR); - if (new_fd >= 0) { - if (new_fd != 0) { - dup2 (new_fd, 0); /* stdin <- /dev/null */ - close (new_fd); - } - dup2 (0, 1); /* stdout -> /dev/null */ - dup2 (0, 2); /* stderr -> /dev/null */ - } + /* Ensure that nothing of our device environment is inherited. */ + closelog(); + if (the_channel->close) + (*the_channel->close)(); + + /* Don't pass handles to the PPP device, even by accident. */ + dup2(fd_devnull, 0); + dup2(fd_devnull, 1); + dup2(fd_devnull, 2); + close(fd_devnull); #ifdef BSD - /* Force the priority back to zero if pppd is running higher. */ - if (setpriority (PRIO_PROCESS, 0, 0) < 0) - warn("can't reset priority to 0: %m"); + /* Force the priority back to zero if pppd is running higher. */ + if (setpriority (PRIO_PROCESS, 0, 0) < 0) + warn("can't reset priority to 0: %m"); #endif - /* SysV recommends a second fork at this point. */ + /* SysV recommends a second fork at this point. */ - /* run the program */ - execve(prog, args, script_env); - if (must_exist || errno != ENOENT) { - /* have to reopen the log, there's nowhere else - for the message to go. */ - reopen_log(); - syslog(LOG_ERR, "Can't execute %s: %m", prog); - closelog(); - } - _exit(-1); + /* run the program */ + execve(prog, args, script_env); + if (must_exist || errno != ENOENT) { + /* have to reopen the log, there's nowhere else + for the message to go. */ + reopen_log(); + syslog(LOG_ERR, "Can't execute %s: %m", prog); + closelog(); } - - if (debug) - dbglog("Script %s started (pid %d)", prog, pid); - record_child(pid, prog, done, arg); - - return pid; + _exit(-1); } @@ -1595,22 +1766,37 @@ record_child(pid, prog, done, arg) } } +/* + * childwait_end - we got fed up waiting for the child processes to + * exit, send them all a SIGTERM. + */ +static void +childwait_end(arg) + void *arg; +{ + struct subprocess *chp; + + for (chp = children; chp != NULL; chp = chp->next) { + if (debug) + dbglog("sending SIGTERM to process %d", chp->pid); + kill(chp->pid, SIGTERM); + } + childwait_done = 1; +} /* * reap_kids - get status from any dead child processes, * and log a message for abnormal terminations. */ static int -reap_kids(waitfor) - int waitfor; +reap_kids() { int pid, status; struct subprocess *chp, **prevp; if (n_children == 0) return 0; - while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1 - && pid != 0) { + while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) { for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) { if (chp->pid == pid) { --n_children;