summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTom Yu <tlyu@mit.edu>2001-05-11 03:01:46 +0000
committerTom Yu <tlyu@mit.edu>2001-05-11 03:01:46 +0000
commite3d691e798d0fba454c69eb9a4bedb95211068e0 (patch)
treed531a677e7cb170a794633bc983b78cd2501fa1b /src
parent6b80b42bdbdfce6d8a55732898d33a4fd3ca819a (diff)
downloadkrb5-e3d691e798d0fba454c69eb9a4bedb95211068e0.tar.gz
krb5-e3d691e798d0fba454c69eb9a4bedb95211068e0.tar.xz
krb5-e3d691e798d0fba454c69eb9a4bedb95211068e0.zip
* pty_paranoia.c: New file; do many paranoid checks about ctty
handling by the pty drivers. * Makefile.in: Add rules for pty_paranoia and check-paranoia, which runs pty_paranoia. * configure.in: Define REVOKE_NEEDS_OPEN for Tru64. Add support for program building and run flags for the sake of pty_paranoia. * open_slave.c: Fix somewhat; AIX doesn't like opening the ctty twice, so only do initial open if we special-case it in configure.in, e.g. for Tru64. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13239 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r--src/util/pty/ChangeLog15
-rw-r--r--src/util/pty/Makefile.in10
-rw-r--r--src/util/pty/configure.in4
-rw-r--r--src/util/pty/open_slave.c8
-rw-r--r--src/util/pty/pty_paranoia.c332
5 files changed, 367 insertions, 2 deletions
diff --git a/src/util/pty/ChangeLog b/src/util/pty/ChangeLog
index c17a9e5b0..eda91e588 100644
--- a/src/util/pty/ChangeLog
+++ b/src/util/pty/ChangeLog
@@ -1,3 +1,18 @@
+2001-05-10 Tom Yu <tlyu@mit.edu>
+
+ * pty_paranoia.c: New file; do many paranoid checks about ctty
+ handling by the pty drivers.
+
+ * Makefile.in: Add rules for pty_paranoia and check-paranoia,
+ which runs pty_paranoia.
+
+ * configure.in: Define REVOKE_NEEDS_OPEN for Tru64. Add support
+ for program building and run flags for the sake of pty_paranoia.
+
+ * open_slave.c: Fix somewhat; AIX doesn't like opening the ctty
+ twice, so only do initial open if we special-case it in
+ configure.in, e.g. for Tru64.
+
2001-05-08 Tom Yu <tlyu@mit.edu>
* logwtmp.c: Delete code under "#if 0". Fix reversed test for
diff --git a/src/util/pty/Makefile.in b/src/util/pty/Makefile.in
index 83d61dc63..32687108b 100644
--- a/src/util/pty/Makefile.in
+++ b/src/util/pty/Makefile.in
@@ -6,6 +6,10 @@ RELDIR=../util/pty
SED = sed
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
LIB=pty
LIBMAJOR=1
LIBMINOR=1
@@ -49,6 +53,12 @@ dump-utmp: dump-utmp.o
$(CC) $(LDFLAGS) -o dump-utmp dump-utmp.o
dump-utmp.o: dump-utmp.c
+pty_paranoia: pty_paranoia.o $(COM_ERR_DEPLIB) $(PTY_DEPLIB)
+ $(CC_LINK) -o pty_paranoia pty_paranoia.o $(PTY_LIB) $(COM_ERR_LIB) $(LIBS)
+
+check-paranoia: pty_paranoia
+ $(KRB5_RUN_ENV) ./pty_paranoia
+
install-unix:: install-libs
clean-unix::
diff --git a/src/util/pty/configure.in b/src/util/pty/configure.in
index 8dce22902..480532211 100644
--- a/src/util/pty/configure.in
+++ b/src/util/pty/configure.in
@@ -35,6 +35,8 @@ alpha*-dec-osf*)
AC_DEFINE(HAVE_SETLUID)
LOGINLIBS="$LOGINLIBS -lsecurity"
)
+ AC_MSG_RESULT(will open ctty prior to revoke due to OSF/1 lossage)
+ AC_DEFINE(REVOKE_NEEDS_OPEN)
;;
*-*-solaris*)
AC_DEFINE(PUSH_PTEM)
@@ -257,4 +259,6 @@ KRB5_AC_INET6
AC_C_CONST
KRB5_BUILD_LIBRARY_WITH_DEPS
KRB5_BUILD_LIBOBJS
+KRB5_BUILD_PROGRAM
+KRB5_RUN_FLAGS
V5_AC_OUTPUT_MAKEFILE
diff --git a/src/util/pty/open_slave.c b/src/util/pty/open_slave.c
index 6e80befb2..cc52228b8 100644
--- a/src/util/pty/open_slave.c
+++ b/src/util/pty/open_slave.c
@@ -39,8 +39,8 @@ pty_open_slave(const char *slave, int *fd)
ptyint_void_association();
/*
- * Make a first attempt at acquiring the ctty. This is necessary
- * for several reasons:
+ * Make a first attempt at acquiring the ctty under certain
+ * condisions. This is necessary for several reasons:
*
* Under Irix, if you open a pty slave and then close it, a
* subsequent open of the slave will cause the master to read EOF.
@@ -52,11 +52,13 @@ pty_open_slave(const char *slave, int *fd)
*
* Anyway, sshd seems to make a practice of doing this.
*/
+#if defined(VHANG_FIRST) || defined(REVOKE_NEEDS_OPEN)
retval = pty_open_ctty(slave, fd);
if (retval)
return retval;
if (*fd < 0)
return PTY_OPEN_SLAVE_OPENFAIL;
+#endif
/* chmod and chown the slave. */
if (chmod(slave, 0))
@@ -76,7 +78,9 @@ pty_open_slave(const char *slave, int *fd)
/* Open the pty for real. */
retval = pty_open_ctty(slave, &tmpfd);
+#if defined(VHANG_FIRST) || defined(REVOKE_NEEDS_OPEN)
close(*fd);
+#endif
if (retval) {
*fd = -1;
return PTY_OPEN_SLAVE_OPENFAIL;
diff --git a/src/util/pty/pty_paranoia.c b/src/util/pty/pty_paranoia.c
new file mode 100644
index 000000000..e07e0ff33
--- /dev/null
+++ b/src/util/pty/pty_paranoia.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+/*
+ * This bears some explanation.
+ *
+ * There are multiple child processes and a parent process. These
+ * communicate via pipes (which we assume here to be unidirectional).
+ * The pipes are:
+ *
+ * pp1 - parent -> any children
+ *
+ * p1p - any children -> parent
+ *
+ * p21 - only child2 -> child1
+ *
+ * A parent process will acquire a pty master and slave via
+ * pty_getpty(). It will then fork a process, child1. It then does a
+ * waitpid() for child1, and then writes to child2 via syncpipe pp1.
+ * It then reads from child3 via syncpipe p1p, then closes the
+ * master. It writes to child3 via syncpipe pp1 to indicate that it
+ * has closed the master. It then reads from child3 via syncpipe p1p
+ * and exits with a value appropriate to what it read from child3.
+ *
+ * child1 will acquire the slave as its ctty and fork child2; child1
+ * will exit once it reads from the syncpipe p21 from child2.
+ *
+ * child2 will set a signal handler for SIGHUP and then write to
+ * child1 via syncpipe p21 to indicate that child2 has set up the
+ * handler. It will then read from the syncpipe pp1 from the parent
+ * to confirm that the parent has seen child1 exit, and then checks to
+ * see if it still has a ctty. Under Unix98, and likely earlier
+ * System V derivatives, the exiting of the session leader associated
+ * with a ctty (in this case, child1) will cause the entire session to
+ * lose its ctty.
+ *
+ * child2 will then check to see if it can reopen the slave, and
+ * whether it has a ctty after reopening it. This should fail on most
+ * systems.
+ *
+ * child2 will then fork child3 and immediately exit.
+ *
+ * child3 will write to the syncpipe p1p and read from the syncpipe
+ * pp1. It will then check if it has a ctty and then attempt to
+ * reopen the slave. This should fail. It will then write to the
+ * parent via syncpipe p1p and exit.
+ */
+
+#include <com_err.h>
+#include "libpty.h"
+#include "pty-int.h"
+#include <sys/wait.h>
+#include <stdlib.h>
+
+char *prog;
+int masterfd, slavefd;
+char slave[64], slave2[64];
+pid_t pid1, pid2, pid3;
+int status1, status2;
+int pp1[2], p1p[2], p21[2];
+
+void handler(int);
+void rdsync(int, int *, const char *);
+void wrsync(int, int, const char *);
+void testctty(const char *);
+void child1(void);
+void child2(void);
+void child3(void);
+
+void
+handler(int sig)
+{
+ printf("pid %ld got signal %d\n", (long)getpid(), sig);
+ fflush(stdout);
+ return;
+}
+
+void
+rdsync(int fd, int *status, const char *caller)
+{
+ int n;
+ char c;
+
+ while ((n = read(fd, &c, 1)) < 0) {
+ if (errno != EINTR) {
+ fprintf(stderr, "wrsync: %s", caller);
+ perror("");
+ exit(1);
+ } else {
+ printf("rdsync: %s: got EINTR; looping\n", caller);
+ fflush(stdout);
+ }
+ }
+ if (!n) {
+ fprintf(stderr, "rdsync: %s: unexpected EOF\n", caller);
+ exit(1);
+ }
+ printf("rdsync: %s: got sync byte\n", caller);
+ fflush(stdout);
+ if (status != NULL)
+ *status = c;
+}
+
+void
+wrsync(int fd, int status, const char *caller)
+{
+ int n;
+ char c;
+
+ c = status;
+ while ((n = write(fd, &c, 1)) < 0) {
+ if (errno != EINTR) {
+ fprintf(stderr, "wrsync: %s", caller);
+ perror("");
+ exit(1);
+ } else {
+ printf("wrsync: %s: got EINTR; looping\n", caller);
+ fflush(stdout);
+ }
+ }
+#if 0
+ printf("wrsync: %s: sent sync byte\n", caller);
+#endif
+ fflush(stdout);
+}
+
+void
+testctty(const char *caller)
+{
+ int fd;
+
+ fd = open("/dev/tty", O_RDWR);
+ if (fd < 0) {
+ printf("%s: no ctty\n", caller);
+ } else {
+ printf("%s: have ctty\n", caller);
+ }
+}
+
+void
+child3(void)
+{
+
+ ptyint_void_association();
+ slavefd = open(slave, O_RDWR);
+ if (slavefd < 0) {
+ printf("child3: failed reopen of slave\n");
+ fflush(stdout);
+ exit(0);
+ }
+#ifdef TIOCSTTY
+ ioctl(slavefd, TIOCSTTY, 0);
+#endif
+
+ printf("child3: reopened slave\n");
+ testctty("child3: after reopen of slave");
+ close(slavefd);
+ testctty("child3: after close of slave");
+
+ /*
+ * Sync for parent to close master.
+ */
+ wrsync(p1p[1], 0, "child3->parent");
+ rdsync(pp1[0], NULL, "parent->child3");
+
+ testctty("child3: after close of master");
+ slavefd = open(slave, O_RDWR);
+ if (slavefd < 0) {
+ printf("child3: failed reopen of slave after master close "
+ "errno=%ld (%s)\n", (long)errno, strerror(errno));
+ wrsync(p1p[1], 0, "child3->parent");
+ fflush(stdout);
+ exit(0);
+ }
+ printf("child3: reopened slave after master close\n");
+ testctty("child3: after reopen of slave after master close\n");
+ wrsync(p1p[1], 1, "child3->parent");
+ fflush(stdout);
+ exit(0);
+}
+
+void
+child2(void)
+{
+ struct sigaction sa;
+
+ close(p21[0]);
+ setpgid(0, 0);
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = handler;
+ if (sigaction(SIGHUP, &sa, NULL) < 0) {
+ perror("child2: sigaction");
+ fflush(stdout);
+ exit(1);
+ }
+ printf("child2: set up signal handler\n");
+ testctty("child2: after start");
+ wrsync(p21[1], 0, "child2->child1");
+ rdsync(pp1[0], NULL, "parent->child2");
+ testctty("child2: after child1 exit");
+ close(slavefd);
+ testctty("child2: after close of slavefd");
+ slavefd = open(slave, O_RDWR);
+ if (slavefd < 0) {
+ printf("child2: failed reopen of slave\n");
+ fflush(stdout);
+ exit(0);
+ }
+ printf("child2: reopened slave\n");
+ testctty("child2: after reopen of slave");
+ fflush(stdout);
+ close(slavefd);
+ pid3 = fork();
+ if (!pid3) {
+ child3();
+ } else if (pid3 == -1) {
+ perror("child2: fork of child3");
+ exit(1);
+ }
+ printf("child2: forked child3=%ld\n", (long)pid3);
+ fflush(stdout);
+ exit(0);
+
+}
+
+void
+child1(void)
+{
+
+ close(pp1[1]);
+ close(p1p[0]);
+ close(masterfd);
+ ptyint_void_association();
+ slavefd = open(slave, O_RDWR);
+ if (slavefd < 0) {
+ perror("child1: open slave");
+ exit(1);
+ }
+#ifdef TIOCSTTY
+ ioctl(slavefd, TIOCSTTY, 0);
+#endif
+
+ printf("child1: opened slave\n");
+ testctty("child1: after slave open");
+
+ if (pipe(p21) < 0) {
+ perror("pipe child2->child1");
+ exit(1);
+ }
+ pid2 = fork();
+ if (!pid2) {
+ child2();
+ } else if (pid2 == -1) {
+ perror("child1: fork child2");
+ exit(1);
+ }
+ close(p21[1]);
+ printf("child1: forked child2=%ld\n", (long)pid2);
+ fflush(stdout);
+ rdsync(p21[0], NULL, "child2->child1");
+ exit(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ long retval;
+ int status;
+
+ prog = argv[0];
+
+ retval = pty_getpty(&masterfd, slave, sizeof(slave));
+
+ if (retval) {
+ com_err(prog, retval, "open master");
+ exit(1);
+ }
+ printf("parent: master opened; slave=%s\n", slave);
+ fflush(stdout);
+
+ if (pipe(pp1) < 0) {
+ perror("pipe parent->child1");
+ exit(1);
+ }
+ if (pipe(p1p) < 0) {
+ perror("pipe child1->parent");
+ exit(1);
+ }
+
+ pid1 = fork();
+ if (!pid1) {
+ child1();
+ } else if (pid1 == -1) {
+ perror("fork of child1");
+ exit(1);
+ }
+ printf("parent: forked child1=%ld\n", (long)pid1);
+ fflush(stdout);
+ if (waitpid(pid1, &status1, 0) < 0) {
+ perror("waitpid for child1");
+ exit(1);
+ }
+ printf("parent: child1 exited, status=%d\n", status1);
+ wrsync(pp1[1], 0, "parent->child2");
+ rdsync(p1p[0], NULL, "child3->parent");
+ printf("parent: closing master\n");
+ fflush(stdout);
+ close(masterfd);
+ printf("parent: closed master\n");
+ wrsync(pp1[1], 0, "parent->child3");
+ rdsync(p1p[0], &status, "child3->parent");
+ if (status) {
+ fprintf(stderr, "got status %d\n", status);
+ }
+ exit(status);
+}