X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fmain.c;h=0be799820739344bd9aa45344b19c26a67d68b03;hp=cc329b1bfeaf35465ffa5c1c53e524ebb4ae90bf;hb=66b97cb2741ff687e731834eb6458281df3dd412;hpb=cccb82a2e9bbc20f343bf4ef7550f79566f84758 diff --git a/pppd/main.c b/pppd/main.c index cc329b1..0be7998 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -1,23 +1,46 @@ /* * 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. */ -#define RCSID "$Id: main.c,v 1.115 2002/10/12 01:28:05 fcusack Exp $" +#define RCSID "$Id: main.c,v 1.134 2004/04/12 04:53:00 kad Exp $" #include #include @@ -51,7 +74,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 +113,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 */ @@ -115,6 +140,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; @@ -146,9 +172,11 @@ int ngroups; /* How many groups valid in groups */ static struct timeval start_time; /* Time when link was started. */ 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 +194,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)); @@ -229,6 +257,7 @@ struct protent *protocols[] = { #ifdef AT_CHANGE &atcp_protent, #endif + &eap_protent, NULL }; @@ -253,18 +282,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 +379,6 @@ main(argc, argv) end_pr_log(); } - /* - * Early check for remote number authorization. - */ - if (!auth_number()) { - error("calling number %q is not authorized", remote_number); - exit(EXIT_CNID_AUTH_FAILED); - } - if (dryrun) die(0); @@ -378,6 +387,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 +438,6 @@ main(argc, argv) waiting = 0; - create_linkpidfile(); - /* * If we're doing dial-on-demand, set up the interface now. */ @@ -439,6 +457,7 @@ main(argc, argv) * Configure the interface and mark it up, etc. */ demand_conf(); + create_linkpidfile(getpid()); } do_callback = 0; @@ -495,6 +514,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 +589,8 @@ main(argc, argv) */ disconnect: new_phase(PHASE_DISCONNECT); - the_channel->disconnect(); + if (the_channel->disconnect) + the_channel->disconnect(); fail: if (the_channel->cleanup) @@ -758,8 +781,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 +794,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 +807,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 +849,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 +866,8 @@ create_pidfile() } static void -create_linkpidfile() +create_linkpidfile(pid) + int pid; { FILE *pidfile; @@ -844,7 +877,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 +1023,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 +1033,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 +1065,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. */ @@ -1097,6 +1173,7 @@ 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; } } @@ -1116,11 +1193,11 @@ update_link_stats(u) link_connect_time = now.tv_sec - start_time.tv_sec; link_stats_valid = 1; - slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time); + slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time); script_setenv("CONNECT_TIME", numbuf, 0); - slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out); + slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out); script_setenv("BYTES_SENT", numbuf, 0); - slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in); + slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_in); script_setenv("BYTES_RCVD", numbuf, 0); } @@ -1253,6 +1330,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 +1338,23 @@ kill_my_pg(sig) { struct sigaction act, oldact; + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, sig); + 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); } @@ -1379,6 +1471,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 +1517,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 +1547,39 @@ 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)(); closelog(); + close(fd_devnull); /* dup the in, out, err fds to 0, 1, 2 */ dup2(in, 0); @@ -1504,66 +1639,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); }