[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.8

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