diff options
author | markm <markm@FreeBSD.org> | 1997-09-04 06:04:33 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 1997-09-04 06:04:33 +0000 |
commit | a8a89cfaf983bc64f4b42f7c35209a5a36dd0fe8 (patch) | |
tree | 0b84977f19022a965f8c6145f067f951173f6290 /crypto/kerberosIV/appl/bsd/forkpty.c | |
download | FreeBSD-src-a8a89cfaf983bc64f4b42f7c35209a5a36dd0fe8.zip FreeBSD-src-a8a89cfaf983bc64f4b42f7c35209a5a36dd0fe8.tar.gz |
Initial import of KTH eBones. This has been cleaned up to only include
the "core" Kerberos functionality. The rest of the userland will get their
own changes later.
Diffstat (limited to 'crypto/kerberosIV/appl/bsd/forkpty.c')
-rw-r--r-- | crypto/kerberosIV/appl/bsd/forkpty.c | 461 |
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 */ |