[BACK]Return to pty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/pty.c, Revision 1.6

1.1       deraadt     1: /*
                      2:
                      3: pty.c
                      4:
                      5: Author: Tatu Ylonen <ylo@cs.hut.fi>
                      6:
                      7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      8:                    All rights reserved
                      9:
                     10: Created: Fri Mar 17 04:37:25 1995 ylo
                     11:
                     12: Allocating a pseudo-terminal, and making it the controlling tty.
                     13:
                     14: */
                     15:
                     16: #include "includes.h"
1.6     ! markus     17: RCSID("$Id: pty.c,v 1.5 1999/10/16 20:57:52 deraadt Exp $");
1.1       deraadt    18:
                     19: #include "pty.h"
                     20: #include "ssh.h"
                     21:
                     22: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
                     23: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
                     24: #undef HAVE_DEV_PTMX
                     25: #endif
                     26:
                     27: #ifndef O_NOCTTY
                     28: #define O_NOCTTY 0
                     29: #endif
                     30:
                     31: /* Allocates and opens a pty.  Returns 0 if no pty could be allocated,
                     32:    or nonzero if a pty was successfully allocated.  On success, open file
1.6     ! markus     33:    descriptors for the pty and tty sides and the name of the tty side are
1.1       deraadt    34:    returned (the buffer must be able to hold at least 64 characters). */
                     35:
1.6     ! markus     36: int
        !            37: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
1.1       deraadt    38: {
                     39: #ifdef HAVE_OPENPTY
1.6     ! markus     40:        /* openpty(3) exists in OSF/1 and some other os'es */
        !            41:        int i;
1.1       deraadt    42:
1.6     ! markus     43:        i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
        !            44:        if (i < 0) {
        !            45:                error("openpty: %.100s", strerror(errno));
        !            46:                return 0;
        !            47:        }
        !            48:        return 1;
1.1       deraadt    49: #else /* HAVE_OPENPTY */
                     50: #ifdef HAVE__GETPTY
1.6     ! markus     51:        /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
        !            52:           more pty's automagically when needed */
        !            53:        char *slave;
        !            54:
        !            55:        slave = _getpty(ptyfd, O_RDWR, 0622, 0);
        !            56:        if (slave == NULL) {
        !            57:                error("_getpty: %.100s", strerror(errno));
        !            58:                return 0;
        !            59:        }
        !            60:        strcpy(namebuf, slave);
        !            61:        /* Open the slave side. */
        !            62:        *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
        !            63:        if (*ttyfd < 0) {
        !            64:                error("%.200s: %.100s", namebuf, strerror(errno));
        !            65:                close(*ptyfd);
        !            66:                return 0;
        !            67:        }
        !            68:        return 1;
1.1       deraadt    69: #else /* HAVE__GETPTY */
                     70: #ifdef HAVE_DEV_PTMX
1.6     ! markus     71:        /* This code is used e.g. on Solaris 2.x.  (Note that Solaris 2.3
        !            72:           also has bsd-style ptys, but they simply do not work.) */
        !            73:        int ptm;
        !            74:        char *pts;
        !            75:
        !            76:        ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
        !            77:        if (ptm < 0) {
        !            78:                error("/dev/ptmx: %.100s", strerror(errno));
        !            79:                return 0;
        !            80:        }
        !            81:        if (grantpt(ptm) < 0) {
        !            82:                error("grantpt: %.100s", strerror(errno));
        !            83:                return 0;
        !            84:        }
        !            85:        if (unlockpt(ptm) < 0) {
        !            86:                error("unlockpt: %.100s", strerror(errno));
        !            87:                return 0;
        !            88:        }
        !            89:        pts = ptsname(ptm);
        !            90:        if (pts == NULL)
        !            91:                error("Slave pty side name could not be obtained.");
        !            92:        strcpy(namebuf, pts);
        !            93:        *ptyfd = ptm;
        !            94:
        !            95:        /* Open the slave side. */
        !            96:        *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
        !            97:        if (*ttyfd < 0) {
        !            98:                error("%.100s: %.100s", namebuf, strerror(errno));
        !            99:                close(*ptyfd);
        !           100:                return 0;
        !           101:        }
        !           102:        /* Push the appropriate streams modules, as described in Solaris
        !           103:           pts(7). */
        !           104:        if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
        !           105:                error("ioctl I_PUSH ptem: %.100s", strerror(errno));
        !           106:        if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
        !           107:                error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
        !           108:        if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
        !           109:                error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
        !           110:        return 1;
1.1       deraadt   111: #else /* HAVE_DEV_PTMX */
                    112: #ifdef HAVE_DEV_PTS_AND_PTC
1.6     ! markus    113:        /* AIX-style pty code. */
        !           114:        const char *name;
1.1       deraadt   115:
1.6     ! markus    116:        *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
        !           117:        if (*ptyfd < 0) {
        !           118:                error("Could not open /dev/ptc: %.100s", strerror(errno));
        !           119:                return 0;
        !           120:        }
        !           121:        name = ttyname(*ptyfd);
        !           122:        if (!name)
        !           123:                fatal("Open of /dev/ptc returns device for which ttyname fails.");
        !           124:        strcpy(namebuf, name);
        !           125:        *ttyfd = open(name, O_RDWR | O_NOCTTY);
        !           126:        if (*ttyfd < 0) {
        !           127:                error("Could not open pty slave side %.100s: %.100s",
        !           128:                      name, strerror(errno));
        !           129:                close(*ptyfd);
        !           130:                return 0;
        !           131:        }
        !           132:        return 1;
1.1       deraadt   133: #else /* HAVE_DEV_PTS_AND_PTC */
1.6     ! markus    134:        /* BSD-style pty code. */
        !           135:        char buf[64];
        !           136:        int i;
        !           137:        const char *ptymajors =
        !           138:        "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
        !           139:        const char *ptyminors = "0123456789abcdef";
        !           140:        int num_minors = strlen(ptyminors);
        !           141:        int num_ptys = strlen(ptymajors) * num_minors;
        !           142:
        !           143:        for (i = 0; i < num_ptys; i++) {
        !           144:                snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
        !           145:                         ptyminors[i % num_minors]);
        !           146:                *ptyfd = open(buf, O_RDWR | O_NOCTTY);
        !           147:                if (*ptyfd < 0)
        !           148:                        continue;
        !           149:                snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
        !           150:                         ptyminors[i % num_minors]);
        !           151:
        !           152:                /* Open the slave side. */
        !           153:                *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
        !           154:                if (*ttyfd < 0) {
        !           155:                        error("%.100s: %.100s", namebuf, strerror(errno));
        !           156:                        close(*ptyfd);
        !           157:                        return 0;
        !           158:                }
        !           159:                return 1;
        !           160:        }
        !           161:        return 0;
1.1       deraadt   162: #endif /* HAVE_DEV_PTS_AND_PTC */
                    163: #endif /* HAVE_DEV_PTMX */
                    164: #endif /* HAVE__GETPTY */
                    165: #endif /* HAVE_OPENPTY */
                    166: }
                    167:
1.6     ! markus    168: /* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
1.1       deraadt   169:
1.6     ! markus    170: void
        !           171: pty_release(const char *ttyname)
1.1       deraadt   172: {
1.6     ! markus    173:        if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
        !           174:                debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
        !           175:        if (chmod(ttyname, (mode_t) 0666) < 0)
        !           176:                debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
1.1       deraadt   177: }
                    178:
                    179: /* Makes the tty the processes controlling tty and sets it to sane modes. */
                    180:
1.6     ! markus    181: void
        !           182: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
1.1       deraadt   183: {
1.6     ! markus    184:        int fd;
1.1       deraadt   185:
1.6     ! markus    186:        /* First disconnect from the old controlling tty. */
1.1       deraadt   187: #ifdef TIOCNOTTY
1.6     ! markus    188:        fd = open("/dev/tty", O_RDWR | O_NOCTTY);
        !           189:        if (fd >= 0) {
        !           190:                (void) ioctl(fd, TIOCNOTTY, NULL);
        !           191:                close(fd);
        !           192:        }
1.1       deraadt   193: #endif /* TIOCNOTTY */
1.6     ! markus    194:        if (setsid() < 0)
        !           195:                error("setsid: %.100s", strerror(errno));
1.1       deraadt   196:
1.6     ! markus    197:        /* Verify that we are successfully disconnected from the
        !           198:           controlling tty. */
        !           199:        fd = open("/dev/tty", O_RDWR | O_NOCTTY);
        !           200:        if (fd >= 0) {
        !           201:                error("Failed to disconnect from controlling tty.");
        !           202:                close(fd);
        !           203:        }
        !           204:        /* Make it our controlling tty. */
1.1       deraadt   205: #ifdef TIOCSCTTY
1.6     ! markus    206:        debug("Setting controlling tty using TIOCSCTTY.");
        !           207:        /* We ignore errors from this, because HPSUX defines TIOCSCTTY,
        !           208:           but returns EINVAL with these arguments, and there is
        !           209:           absolutely no documentation. */
        !           210:        ioctl(*ttyfd, TIOCSCTTY, NULL);
1.1       deraadt   211: #endif /* TIOCSCTTY */
1.6     ! markus    212:        fd = open(ttyname, O_RDWR);
        !           213:        if (fd < 0)
        !           214:                error("%.100s: %.100s", ttyname, strerror(errno));
        !           215:        else
        !           216:                close(fd);
        !           217:
        !           218:        /* Verify that we now have a controlling tty. */
        !           219:        fd = open("/dev/tty", O_WRONLY);
        !           220:        if (fd < 0)
        !           221:                error("open /dev/tty failed - could not set controlling tty: %.100s",
        !           222:                      strerror(errno));
        !           223:        else {
        !           224:                close(fd);
        !           225:        }
1.1       deraadt   226: }
                    227:
                    228: /* Changes the window size associated with the pty. */
                    229:
1.6     ! markus    230: void
        !           231: pty_change_window_size(int ptyfd, int row, int col,
        !           232:                       int xpixel, int ypixel)
1.1       deraadt   233: {
1.6     ! markus    234:        struct winsize w;
        !           235:        w.ws_row = row;
        !           236:        w.ws_col = col;
        !           237:        w.ws_xpixel = xpixel;
        !           238:        w.ws_ypixel = ypixel;
        !           239:        (void) ioctl(ptyfd, TIOCSWINSZ, &w);
1.1       deraadt   240: }