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

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