summaryrefslogtreecommitdiffstats
path: root/crypto/kerberosIV/appl/bsd/forkpty.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/kerberosIV/appl/bsd/forkpty.c')
-rw-r--r--crypto/kerberosIV/appl/bsd/forkpty.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/crypto/kerberosIV/appl/bsd/forkpty.c b/crypto/kerberosIV/appl/bsd/forkpty.c
new file mode 100644
index 0000000..5c0aaaf
--- /dev/null
+++ b/crypto/kerberosIV/appl/bsd/forkpty.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "bsd_locl.h"
+
+#ifndef HAVE_FORKPTY
+
+RCSID("$Id: forkpty.c,v 1.52 1997/05/25 07:37:01 assar Exp $");
+
+/* Only CRAY is known to have problems with forkpty(). */
+#if defined(CRAY)
+static int forkpty_ok = 0;
+#else
+static int forkpty_ok = 1;
+#endif
+
+#ifndef HAVE_PTSNAME
+static char *ptsname(int fd)
+{
+#ifdef HAVE_TTYNAME
+ return ttyname(fd);
+#else
+ return NULL;
+#endif
+}
+#endif
+
+#ifndef HAVE_GRANTPT
+#define grantpt(fdm) (0)
+#endif
+
+#ifndef HAVE_UNLOCKPT
+#define unlockpt(fdm) (0)
+#endif
+
+#ifndef HAVE_VHANGUP
+#define vhangup() (0)
+#endif
+
+#ifndef HAVE_REVOKE
+static
+void
+revoke(char *line)
+{
+ int slave;
+ RETSIGTYPE (*ofun)();
+
+ if ( (slave = open(line, O_RDWR)) < 0)
+ return;
+
+ ofun = signal(SIGHUP, SIG_IGN);
+ vhangup();
+ signal(SIGHUP, ofun);
+ /*
+ * Some systems (atleast SunOS4) want to have the slave end open
+ * at all times to prevent a race in the child. Login will close
+ * it so it should really not be a problem. However for the
+ * paranoid we use the close on exec flag so it will only be open
+ * in the parent. Additionally since this will be the controlling
+ * tty of rlogind the final vhangup() in rlogind should hangup all
+ * processes. A working revoke would of course have been prefered
+ * though (sigh).
+ */
+ fcntl(slave, F_SETFD, 1);
+ /* close(slave); */
+}
+#endif
+
+
+static int pty_major, pty_minor;
+
+static void
+pty_scan_start(void)
+{
+ pty_major = -1;
+ pty_minor = 0;
+}
+
+static char *bsd_1 = "0123456789abcdefghijklmnopqrstuv";
+/* there are many more */
+static char *bsd_2 = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static int
+pty_scan_next(char *buf, size_t sz)
+{
+#ifdef CRAY
+ if(++pty_major >= sysconf(_SC_CRAY_NPTY))
+ return -1;
+ snprintf(buf, sz, "/dev/pty/%03d", pty_major);
+#else
+ if(++pty_major == strlen(bsd_1)){
+ pty_major = 0;
+ if(++pty_minor == strlen(bsd_2))
+ return -1;
+ }
+#ifdef __hpux
+ snprintf(buf, sz, "/dev/ptym/pty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
+#else
+ snprintf(buf, sz, "/dev/pty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
+#endif /* __hpux */
+#endif /* CRAY */
+ return 0;
+}
+
+static void
+pty_scan_tty(char *buf, size_t sz)
+{
+#ifdef CRAY
+ snprintf(buf, sz, "/dev/ttyp%03d", pty_major);
+#elif defined(__hpux)
+ snprintf(buf, sz, "/dev/pty/tty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
+#else
+ snprintf(buf, sz, "/dev/tty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
+#endif
+}
+
+static int
+ptym_open_streams_flavor(char *pts_name, int *streams_pty)
+{
+ /* Try clone device master ptys */
+ const char *const clone[] = { "/dev/ptc", "/dev/ptmx",
+ "/dev/ptm", "/dev/ptym/clone", 0 };
+ int fdm;
+ const char *const *q;
+
+ for (q = clone; *q; q++) {
+ fdm = open(*q, O_RDWR);
+ if (fdm >= 0)
+ break;
+ }
+ if (fdm >= 0) {
+ char *ptr1;
+ if ((ptr1 = ptsname(fdm)) != NULL) /* Get slave's name */
+ strcpy(pts_name, ptr1); /* Return name of slave */
+ else {
+ close(fdm);
+ return(-4);
+ }
+ if (grantpt(fdm) < 0) { /* Grant access to slave */
+ close(fdm);
+ return(-2);
+ }
+ if (unlockpt(fdm) < 0) { /* Clear slave's lock flag */
+ close(fdm);
+ return(-3);
+ }
+ return(fdm); /* return fd of master */
+ }
+ return -1;
+}
+
+static int
+ptym_open_bsd_flavor(char *pts_name, int *streams_pty)
+{
+ int fdm;
+ char ptm[MaxPathLen];
+
+ pty_scan_start();
+
+ while (pty_scan_next(ptm, sizeof(ptm)) != -1) {
+ fdm = open(ptm, O_RDWR);
+ if (fdm < 0)
+ continue;
+#if SunOS == 4
+ /* Avoid a bug in SunOS4 ttydriver */
+ if (fdm > 0) {
+ int pgrp;
+ if ((ioctl(fdm, TIOCGPGRP, &pgrp) == -1)
+ && (errno == EIO))
+ /* All fine */;
+ else {
+ close(fdm);
+ continue;
+ }
+ }
+#endif
+ pty_scan_tty(pts_name, sizeof(ptm));
+#if CRAY
+ /* this is some magic from the telnet code */
+ {
+ struct stat sb;
+ if(stat(pts_name, &sb) < 0) {
+ close(fdm);
+ continue;
+ }
+ if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
+ chown(pts_name, 0, 0);
+ chmod(pts_name, 0600);
+ close(fdm);
+ fdm = open(ptm, 2);
+ if (fdm < 0)
+ continue;
+ }
+ }
+ /*
+ * Now it should be safe...check for accessability.
+ */
+ if (access(pts_name, 6) != 0){
+ /* no tty side to pty so skip it */
+ close(fdm);
+ continue;
+ }
+#endif
+ return fdm; /* All done! */
+ }
+
+ /* We failed to find BSD style pty */
+ errno = ENOENT;
+ return -1;
+}
+
+/*
+ *
+ * Open a master pty either using the STREAM flavor or the BSD flavor.
+ * Depending on if there are any free ptys in the different classes we
+ * need to try both. Normally try STREAMS first and then BSD.
+ *
+ * Kludge alert: Under HP-UX 10 and perhaps other systems STREAM ptys
+ * doesn't get initialized properly so we try them in different order
+ * until the problem has been resolved.
+ *
+ */
+static int
+ptym_open(char *pts_name, size_t pts_name_sz, int *streams_pty)
+{
+ int fdm;
+
+#ifdef HAVE__GETPTY
+ {
+ char *p = _getpty(&fdm, O_RDWR, 0600, 1);
+ if (p) {
+ *streams_pty = 1;
+ strcpy (pts_name, p);
+ return fdm;
+ }
+ }
+#endif
+
+#ifdef STREAMSPTY
+ fdm = ptym_open_streams_flavor(pts_name, streams_pty);
+ if (fdm >= 0)
+ {
+ *streams_pty = 1;
+ return fdm;
+ }
+#endif
+
+ fdm = ptym_open_bsd_flavor(pts_name, streams_pty);
+ if (fdm >= 0)
+ {
+ *streams_pty = 0;
+ return fdm;
+ }
+
+#ifndef STREAMSPTY
+ fdm = ptym_open_streams_flavor(pts_name, streams_pty);
+ if (fdm >= 0)
+ {
+ *streams_pty = 1;
+ return fdm;
+ }
+#endif
+
+ return -1;
+}
+
+static int
+maybe_push_modules(int fd, char **modules)
+{
+#ifdef I_PUSH
+ char **p;
+ int err;
+
+ for(p=modules; *p; p++){
+ err=ioctl(fd, I_FIND, *p);
+ if(err == 1)
+ break;
+ if(err < 0 && errno != EINVAL)
+ return -17;
+ /* module not pushed or does not exist */
+ }
+ /* p points to null or to an already pushed module, now push all
+ modules before this one */
+
+ for(p--; p >= modules; p--){
+ err = ioctl(fd, I_PUSH, *p);
+ if(err < 0 && errno != EINVAL)
+ return -17;
+ }
+#endif
+ return 0;
+}
+
+static int
+ptys_open(int fdm, char *pts_name, int streams_pty)
+{
+ int fds;
+
+ if (streams_pty) {
+ /* Streams style slave ptys */
+ if ( (fds = open(pts_name, O_RDWR)) < 0) {
+ close(fdm);
+ return(-5);
+ }
+
+ {
+ char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
+ char *ptymodules[] = { "pckt", NULL };
+
+ if(maybe_push_modules(fds, ttymodules)<0){
+ close(fdm);
+ close(fds);
+ return -6;
+ }
+ if(maybe_push_modules(fdm, ptymodules)<0){
+ close(fdm);
+ close(fds);
+ return -7;
+ }
+ }
+ } else {
+ /* BSD style slave ptys */
+ struct group *grptr;
+ int gid;
+ if ( (grptr = getgrnam("tty")) != NULL)
+ gid = grptr->gr_gid;
+ else
+ gid = -1; /* group tty is not in the group file */
+
+ /* Grant access to slave */
+ chown(pts_name, getuid(), gid);
+ chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
+
+ if ( (fds = open(pts_name, O_RDWR)) < 0) {
+ close(fdm);
+ return(-1);
+ }
+ }
+ return(fds);
+}
+
+int
+forkpty(int *ptrfdm,
+ char *slave_name,
+ struct termios *slave_termios,
+ struct winsize *slave_winsize)
+{
+ int fdm, fds, streams_pty;
+ pid_t pid;
+ char pts_name[20];
+
+ if (!forkpty_ok)
+ fatal(0, "Protocol not yet supported, use telnet", 0);
+
+ if ( (fdm = ptym_open(pts_name, sizeof(pts_name), &streams_pty)) < 0)
+ return -1;
+
+ if (slave_name != NULL)
+ strcpy(slave_name, pts_name); /* Return name of slave */
+
+ pid = fork();
+ if (pid < 0)
+ return(-1);
+ else if (pid == 0) { /* Child */
+ if (setsid() < 0)
+ fatal(0, "setsid() failure", errno);
+
+ revoke(slave_name);
+
+#if defined(NeXT) || defined(ultrix)
+ /* The NeXT is severely broken, this makes things slightly
+ * better but we still doesn't get a working pty. If there
+ * where a TIOCSCTTY we could perhaps fix things but... The
+ * same problem also exists in xterm! */
+ if (setpgrp(0, 0) < 0)
+ fatal(0, "NeXT kludge failed setpgrp", errno);
+#endif
+
+ /* SVR4 acquires controlling terminal on open() */
+ if ( (fds = ptys_open(fdm, pts_name, streams_pty)) < 0)
+ return -1;
+ close(fdm); /* All done with master in child */
+
+#if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(__hpux)
+ /* 44BSD way to acquire controlling terminal */
+ /* !CIBAUD to avoid doing this under SunOS */
+ if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
+ return -1;
+#endif
+#if defined(NeXT)
+ {
+ int t = open("/dev/tty", O_RDWR);
+ if (t < 0)
+ fatal(0, "Failed to open /dev/tty", errno);
+ close(fds);
+ fds = t;
+ }
+#endif
+ /* Set slave's termios and window size */
+ if (slave_termios != NULL) {
+ if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
+ return -1;
+ }
+#ifdef TIOCSWINSZ
+ if (slave_winsize != NULL) {
+ if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
+ return -1;
+ }
+#endif
+ /* slave becomes stdin/stdout/stderr of child */
+ if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
+ return -1;
+ if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
+ return -1;
+ if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
+ return -1;
+ if (fds > STDERR_FILENO)
+ close(fds);
+ return(0); /* child returns 0 just like fork() */
+ }
+ else { /* Parent */
+ *ptrfdm = fdm; /* Return fd of master */
+ return(pid); /* Parent returns pid of child */
+ }
+}
+#endif /* HAVE_FORKPTY */
OpenPOWER on IntegriCloud