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

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