X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fmain.c;h=4a91e06e4b846793abe63845260314901224c4ee;hb=d08ae26ec4789b3e3b9f2614b82600b3d646cf59;hp=fe2e953eac94202a4ef469e4addfa4bd9ce040e8;hpb=36e867a96fbc20777c4d3cb15e7aa4f7180f1452;p=ppp.git diff --git a/pppd/main.c b/pppd/main.c index fe2e953..4a91e06 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -38,9 +38,35 @@ * 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.139 2004/11/04 09:46:50 paulus Exp $" +#define RCSID "$Id: main.c,v 1.144 2004/11/09 22:35:02 paulus Exp $" #include #include @@ -387,11 +413,6 @@ main(argc, argv) if (dryrun) die(0); - /* - * Initialize system-dependent stuff. - */ - sys_init(); - /* Make sure fds 0, 1, 2 are open to somewhere. */ fd_devnull = open(_PATH_DEVNULL, O_RDWR); if (fd_devnull < 0) @@ -403,6 +424,11 @@ main(argc, argv) fd_devnull = i; } + /* + * Initialize system-dependent stuff. + */ + sys_init(); + #ifdef USE_TDB pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644); if (pppdb != NULL) { @@ -673,12 +699,14 @@ handle_events() 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; @@ -845,12 +873,8 @@ detach() void reopen_log() { -#ifdef ULTRIX - openlog("pppd", LOG_PID); -#else openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); setlogmask(LOG_UPTO(LOG_INFO)); -#endif } /* @@ -1248,9 +1272,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. */ @@ -1289,8 +1310,6 @@ untimeout(func, arg) { struct callout **copp, *freep; - MAINDEBUG(("Untimeout %p:%p.", func, arg)); - /* * Find first matching timeout and remove it from the list. */ @@ -1394,7 +1413,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 */ @@ -1415,8 +1434,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); @@ -1498,34 +1517,83 @@ bad_signal(sig) * 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. + * This also arranges for the specified fds to be dup'd to + * fds 0, 1, 2 in the child. */ pid_t -safe_fork() +safe_fork(int infd, int outfd, int errfd) { pid_t pid; - int pipefd[2]; + int fd, pipefd[2]; char buf[1]; + /* make sure fds 0, 1, 2 are occupied (probably not necessary) */ + while ((fd = dup(fd_devnull)) >= 0) { + if (fd > 2) { + close(fd); + break; + } + } + if (pipe(pipefd) == -1) pipefd[0] = pipefd[1] = -1; pid = fork(); - if (pid < 0) + if (pid < 0) { + error("fork failed: %m"); return -1; + } if (pid > 0) { + /* parent */ close(pipefd[1]); /* this read() blocks until the close(pipefd[1]) below */ complete_read(pipefd[0], buf, 1); close(pipefd[0]); return pid; } + + /* Executing in the child */ sys_close(); #ifdef USE_TDB tdb_close(pppdb); #endif + + /* make sure infd, outfd and errfd won't get tromped on below */ + if (infd == 1 || infd == 2) + infd = dup(infd); + if (outfd == 0 || outfd == 2) + outfd = dup(outfd); + if (errfd == 0 || errfd == 1) + errfd = dup(errfd); + + /* dup the in, out, err fds to 0, 1, 2 */ + if (infd != 0) + dup2(infd, 0); + if (outfd != 1) + dup2(outfd, 1); + if (errfd != 2) + dup2(errfd, 2); + + closelog(); + if (log_to_fd > 2) + close(log_to_fd); + if (the_channel->close) + (*the_channel->close)(); + else + close(devfd); /* some plugins don't have a close function */ + close(fd_ppp); + close(fd_devnull); + if (infd != 0) + close(infd); + if (outfd != 1) + close(outfd); + if (errfd != 2) + close(errfd); + notify(fork_notifier, 0); close(pipefd[0]); /* this close unblocks the read() call above in the parent */ close(pipefd[1]); + return 0; } @@ -1543,10 +1611,17 @@ device_script(program, in, out, dont_wait) int pid; int status = -1; int errfd; - int fd; + + if (log_to_fd >= 0) + errfd = log_to_fd; + else + errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); ++conn_running; - pid = safe_fork(); + pid = safe_fork(in, out, errfd); + + if (pid != 0 && log_to_fd < 0) + close(errfd); if (pid < 0) { --conn_running; @@ -1571,59 +1646,14 @@ 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) { - close(fd); - break; - } - } - - /* dup in and out to fds > 2 */ - { - 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); - 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); - close(in); - dup2(out, 1); - close(out); - if (errfd >= 0) { - dup2(errfd, 2); - close(errfd); - } - + setgid(getgid()); setuid(uid); if (getuid() != uid) { - error("setuid failed"); + fprintf(stderr, "pppd: setuid failed\n"); exit(1); } - setgid(getgid()); execl("/bin/sh", "sh", "-c", program, (char *)0); - error("could not exec /bin/sh: %m"); + perror("pppd: could not exec /bin/sh"); exit(99); /* NOTREACHED */ } @@ -1664,7 +1694,7 @@ run_program(prog, args, must_exist, done, arg) return 0; } - pid = safe_fork(); + pid = safe_fork(fd_devnull, fd_devnull, fd_devnull); if (pid == -1) { error("Failed to create child process for %s: %m", prog); return -1; @@ -1683,25 +1713,12 @@ run_program(prog, args, must_exist, done, arg) setuid(0); /* set real UID = root */ setgid(getegid()); - /* 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"); #endif - /* SysV recommends a second fork at this point. */ - /* run the program */ execve(prog, args, script_env); if (must_exist || errno != ENOENT) {