ones we want on fds 0, 1, 2.
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: main.c,v 1.142 2004/11/04 10:05:23 paulus Exp $"
+#define RCSID "$Id: main.c,v 1.143 2004/11/06 05:42:29 paulus Exp $"
#include <stdio.h>
#include <ctype.h>
void
reopen_log()
{
-#ifdef ULTRIX
- openlog("pppd", LOG_PID);
-#else
openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
setlogmask(LOG_UPTO(LOG_INFO));
-#endif
}
/*
* 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;
}
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;
/* 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 */
}
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;
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) {
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: pppd.h,v 1.85 2004/11/04 09:46:50 paulus Exp $
+ * $Id: pppd.h,v 1.86 2004/11/06 05:42:29 paulus Exp $
*/
/*
extern char ppp_devnam[MAXPATHLEN];
extern char remote_number[MAXNAMELEN]; /* Remote telephone number, if avail. */
extern int ppp_session_number; /* Session number (eg PPPoE session) */
+extern int fd_devnull; /* fd open to /dev/null */
extern int listen_time; /* time to listen first (ms) */
extern struct notifier *pidchange; /* for notifications of pid changing */
void untimeout __P((void (*func)(void *), void *arg));
/* Cancel call to func(arg) */
void record_child __P((int, char *, void (*) (void *), void *));
-pid_t safe_fork __P((void)); /* Fork & close stuff in child */
+pid_t safe_fork __P((int, int, int)); /* Fork & close stuff in child */
int device_script __P((char *cmd, int in, int out, int dont_wait));
/* Run `cmd' with given stdin and stdout */
pid_t run_program __P((char *prog, char **args, int must_exist,
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: tty.c,v 1.18 2004/11/04 10:02:26 paulus Exp $"
+#define RCSID "$Id: tty.c,v 1.19 2004/11/06 05:42:29 paulus Exp $"
#include <stdio.h>
#include <ctype.h>
status = EXIT_LOCK_FAILED;
if (lockflag && !privopen) {
if (lock(devnam) < 0)
- return -1;
+ goto errret;
locked = 1;
}
prio = privopen? OPRIO_ROOT: tty_options[0].priority;
if (prio < OPRIO_ROOT)
seteuid(uid);
- ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+ real_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
if (prio < OPRIO_ROOT)
seteuid(0);
- if (ttyfd >= 0)
+ if (real_ttyfd >= 0)
break;
errno = err;
if (err != EINTR) {
status = EXIT_OPEN_FAILED;
}
if (!persist || err != EINTR)
- return -1;
+ goto errret;
}
- real_ttyfd = ttyfd;
+ ttyfd = real_ttyfd;
if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
|| fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
warn("Couldn't reset non-blocking mode on device: %m");
close(opipe[0]);
close(opipe[1]);
if (!ok)
- return -1;
+ goto errret;
} else {
if (device_script(ptycommand, pty_master, pty_master, 1) < 0)
- return -1;
- ttyfd = pty_slave;
- close(pty_master);
- pty_master = -1;
+ goto errret;
}
} else if (pty_socket != NULL) {
int fd = open_socket(pty_socket);
if (fd < 0)
- return -1;
+ goto errret;
if (!start_charshunt(fd, fd))
- return -1;
+ goto errret;
+ close(fd);
} else if (notty) {
if (!start_charshunt(0, 1))
- return -1;
+ goto errret;
} else if (record_file != NULL) {
- if (!start_charshunt(ttyfd, ttyfd))
- return -1;
+ int fd = dup(ttyfd);
+ if (!start_charshunt(fd, fd))
+ goto errret;
}
- if (using_pty || record_file != NULL)
+ if (using_pty || record_file != NULL) {
ttyfd = pty_slave;
+ close(pty_master);
+ pty_master = -1;
+ }
/* run connection script */
if ((connector && connector[0]) || initializer) {
if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
error("Initializer script failed");
status = EXIT_INIT_FAILED;
- return -1;
+ goto errret;
}
if (kill_link) {
disconnect_tty();
- return -1;
+ goto errret;
}
info("Serial port initialized.");
}
if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
error("Connect script failed");
status = EXIT_CONNECT_FAILED;
- return -1;
+ goto errret;
}
if (kill_link) {
disconnect_tty();
- return -1;
+ goto errret;
}
info("Serial connection established.");
}
status = EXIT_OPEN_FAILED;
}
if (!persist || errno != EINTR || hungup || kill_link)
- return -1;
+ goto errret;
}
close(i);
}
listen_time = connect_delay;
return ttyfd;
+
+ errret:
+ if (pty_master >= 0) {
+ close(pty_master);
+ pty_master = -1;
+ }
+ if (pty_slave >= 0) {
+ close(pty_slave);
+ pty_slave = -1;
+ }
+ if (real_ttyfd >= 0) {
+ close(real_ttyfd);
+ real_ttyfd = -1;
+ }
+ ttyfd = -1;
+ return -1;
}
void tty_close_fds()
{
- if (pty_master >= 0)
- close(pty_master);
if (pty_slave >= 0)
close(pty_slave);
if (real_ttyfd >= 0) {
{
int cpid;
- cpid = safe_fork();
+ cpid = safe_fork(ifd, ofd, (log_to_fd >= 0? log_to_fd: 2));
if (cpid == -1) {
error("Can't fork process for character shunt: %m");
return 0;
}
if (cpid == 0) {
/* child */
- close(pty_slave);
+ reopen_log();
+ if (!nodetach)
+ log_to_fd = -1;
+ else if (log_to_fd >= 0)
+ log_to_fd = 2;
+ setgid(getgid());
setuid(uid);
if (getuid() != uid)
fatal("setuid failed");
- setgid(getgid());
- if (!nodetach)
- log_to_fd = -1;
- charshunt(ifd, ofd, record_file);
+ charshunt(0, 1, record_file);
exit(0);
}
charshunt_pid = cpid;
add_notifier(&sigreceived, stop_charshunt, 0);
- close(pty_master);
- pty_master = -1;
record_child(cpid, "pppd (charshunt)", charshunt_done, NULL);
return 1;
}
} else if (nibuf == 0) {
/* end of file from stdin */
stdin_readable = 0;
- /* do a 0-length write, hopefully this will generate
- an EOF (hangup) on the slave side. */
- write(pty_master, inpacket_buf, 0);
if (recordf)
if (!record_write(recordf, 4, NULL, 0, &lasttime))
recordf = NULL;
if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
recordf = NULL;
}
- }
+ } else if (!stdin_readable)
+ pty_readable = 0;
if (FD_ISSET(ofd, &writey)) {
n = nobuf;
if (olevel + n > max_level)