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

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.15    ! deraadt     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".
        !            12:  *
        !            13:  *
        !            14:  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
        !            15:  *
        !            16:  * Redistribution and use in source and binary forms, with or without
        !            17:  * modification, are permitted provided that the following conditions
        !            18:  * are met:
        !            19:  * 1. Redistributions of source code must retain the above copyright
        !            20:  *    notice, this list of conditions and the following disclaimer.
        !            21:  * 2. Redistributions in binary form must reproduce the above copyright
        !            22:  *    notice, this list of conditions and the following disclaimer in the
        !            23:  *    documentation and/or other materials provided with the distribution.
        !            24:  *
        !            25:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            27:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            28:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            29:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            30:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            31:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            32:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            33:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            34:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.7       deraadt    35:  */
1.1       deraadt    36:
                     37: #include "includes.h"
1.15    ! deraadt    38: RCSID("$OpenBSD: pty.c,v 1.14 2000/06/20 01:39:43 markus Exp $");
1.1       deraadt    39:
1.10      deraadt    40: #include <util.h>
1.1       deraadt    41: #include "pty.h"
                     42: #include "ssh.h"
                     43:
                     44: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
                     45: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
                     46: #undef HAVE_DEV_PTMX
                     47: #endif
                     48:
                     49: #ifndef O_NOCTTY
                     50: #define O_NOCTTY 0
                     51: #endif
                     52:
1.8       markus     53: /*
                     54:  * Allocates and opens a pty.  Returns 0 if no pty could be allocated, or
                     55:  * nonzero if a pty was successfully allocated.  On success, open file
                     56:  * descriptors for the pty and tty sides and the name of the tty side are
                     57:  * returned (the buffer must be able to hold at least 64 characters).
                     58:  */
1.1       deraadt    59:
1.13      markus     60: int
1.9       deraadt    61: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
1.1       deraadt    62: {
1.9       deraadt    63: #if defined(HAVE_OPENPTY) || defined(BSD4_4)
1.6       markus     64:        /* openpty(3) exists in OSF/1 and some other os'es */
1.9       deraadt    65:        char buf[64];
1.6       markus     66:        int i;
1.1       deraadt    67:
1.9       deraadt    68:        i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
1.6       markus     69:        if (i < 0) {
                     70:                error("openpty: %.100s", strerror(errno));
                     71:                return 0;
                     72:        }
1.9       deraadt    73:        strlcpy(namebuf, buf, namebuflen);      /* possible truncation */
1.6       markus     74:        return 1;
1.1       deraadt    75: #else /* HAVE_OPENPTY */
                     76: #ifdef HAVE__GETPTY
1.8       markus     77:        /*
                     78:         * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
                     79:         * pty's automagically when needed
                     80:         */
1.6       markus     81:        char *slave;
                     82:
                     83:        slave = _getpty(ptyfd, O_RDWR, 0622, 0);
                     84:        if (slave == NULL) {
                     85:                error("_getpty: %.100s", strerror(errno));
                     86:                return 0;
                     87:        }
1.9       deraadt    88:        strlcpy(namebuf, slave, namebuflen);
1.6       markus     89:        /* Open the slave side. */
                     90:        *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
                     91:        if (*ttyfd < 0) {
                     92:                error("%.200s: %.100s", namebuf, strerror(errno));
                     93:                close(*ptyfd);
                     94:                return 0;
                     95:        }
                     96:        return 1;
1.1       deraadt    97: #else /* HAVE__GETPTY */
                     98: #ifdef HAVE_DEV_PTMX
1.8       markus     99:        /*
                    100:         * This code is used e.g. on Solaris 2.x.  (Note that Solaris 2.3
                    101:         * also has bsd-style ptys, but they simply do not work.)
                    102:         */
1.6       markus    103:        int ptm;
                    104:        char *pts;
                    105:
                    106:        ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
                    107:        if (ptm < 0) {
                    108:                error("/dev/ptmx: %.100s", strerror(errno));
                    109:                return 0;
                    110:        }
                    111:        if (grantpt(ptm) < 0) {
                    112:                error("grantpt: %.100s", strerror(errno));
                    113:                return 0;
                    114:        }
                    115:        if (unlockpt(ptm) < 0) {
                    116:                error("unlockpt: %.100s", strerror(errno));
                    117:                return 0;
                    118:        }
                    119:        pts = ptsname(ptm);
                    120:        if (pts == NULL)
                    121:                error("Slave pty side name could not be obtained.");
1.9       deraadt   122:        strlcpy(namebuf, pts, namebuflen);
1.6       markus    123:        *ptyfd = ptm;
                    124:
                    125:        /* Open the slave side. */
                    126:        *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
                    127:        if (*ttyfd < 0) {
                    128:                error("%.100s: %.100s", namebuf, strerror(errno));
                    129:                close(*ptyfd);
                    130:                return 0;
                    131:        }
1.8       markus    132:        /* Push the appropriate streams modules, as described in Solaris pts(7). */
1.6       markus    133:        if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
                    134:                error("ioctl I_PUSH ptem: %.100s", strerror(errno));
                    135:        if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
                    136:                error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
                    137:        if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
                    138:                error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
                    139:        return 1;
1.1       deraadt   140: #else /* HAVE_DEV_PTMX */
                    141: #ifdef HAVE_DEV_PTS_AND_PTC
1.6       markus    142:        /* AIX-style pty code. */
                    143:        const char *name;
1.1       deraadt   144:
1.6       markus    145:        *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
                    146:        if (*ptyfd < 0) {
                    147:                error("Could not open /dev/ptc: %.100s", strerror(errno));
                    148:                return 0;
                    149:        }
                    150:        name = ttyname(*ptyfd);
                    151:        if (!name)
                    152:                fatal("Open of /dev/ptc returns device for which ttyname fails.");
1.9       deraadt   153:        strlcpy(namebuf, name, namebuflen);
1.6       markus    154:        *ttyfd = open(name, O_RDWR | O_NOCTTY);
                    155:        if (*ttyfd < 0) {
                    156:                error("Could not open pty slave side %.100s: %.100s",
                    157:                      name, strerror(errno));
                    158:                close(*ptyfd);
                    159:                return 0;
                    160:        }
                    161:        return 1;
1.1       deraadt   162: #else /* HAVE_DEV_PTS_AND_PTC */
1.6       markus    163:        /* BSD-style pty code. */
                    164:        char buf[64];
                    165:        int i;
1.8       markus    166:        const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
1.6       markus    167:        const char *ptyminors = "0123456789abcdef";
                    168:        int num_minors = strlen(ptyminors);
                    169:        int num_ptys = strlen(ptymajors) * num_minors;
                    170:
                    171:        for (i = 0; i < num_ptys; i++) {
                    172:                snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
                    173:                         ptyminors[i % num_minors]);
                    174:                *ptyfd = open(buf, O_RDWR | O_NOCTTY);
                    175:                if (*ptyfd < 0)
                    176:                        continue;
1.11      markus    177:                snprintf(namebuf, namebuflen, "/dev/tty%c%c",
1.9       deraadt   178:                    ptymajors[i / num_minors], ptyminors[i % num_minors]);
1.6       markus    179:
                    180:                /* Open the slave side. */
                    181:                *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
                    182:                if (*ttyfd < 0) {
                    183:                        error("%.100s: %.100s", namebuf, strerror(errno));
                    184:                        close(*ptyfd);
                    185:                        return 0;
                    186:                }
                    187:                return 1;
                    188:        }
                    189:        return 0;
1.1       deraadt   190: #endif /* HAVE_DEV_PTS_AND_PTC */
                    191: #endif /* HAVE_DEV_PTMX */
                    192: #endif /* HAVE__GETPTY */
                    193: #endif /* HAVE_OPENPTY */
                    194: }
                    195:
1.6       markus    196: /* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
1.1       deraadt   197:
1.13      markus    198: void
1.6       markus    199: pty_release(const char *ttyname)
1.1       deraadt   200: {
1.6       markus    201:        if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
1.12      markus    202:                error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
1.6       markus    203:        if (chmod(ttyname, (mode_t) 0666) < 0)
1.12      markus    204:                error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
1.1       deraadt   205: }
                    206:
                    207: /* Makes the tty the processes controlling tty and sets it to sane modes. */
                    208:
1.13      markus    209: void
1.6       markus    210: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
1.1       deraadt   211: {
1.6       markus    212:        int fd;
1.1       deraadt   213:
1.6       markus    214:        /* First disconnect from the old controlling tty. */
1.1       deraadt   215: #ifdef TIOCNOTTY
1.6       markus    216:        fd = open("/dev/tty", O_RDWR | O_NOCTTY);
                    217:        if (fd >= 0) {
                    218:                (void) ioctl(fd, TIOCNOTTY, NULL);
                    219:                close(fd);
                    220:        }
1.1       deraadt   221: #endif /* TIOCNOTTY */
1.6       markus    222:        if (setsid() < 0)
                    223:                error("setsid: %.100s", strerror(errno));
1.1       deraadt   224:
1.8       markus    225:        /*
                    226:         * Verify that we are successfully disconnected from the controlling
                    227:         * tty.
                    228:         */
1.6       markus    229:        fd = open("/dev/tty", O_RDWR | O_NOCTTY);
                    230:        if (fd >= 0) {
                    231:                error("Failed to disconnect from controlling tty.");
                    232:                close(fd);
                    233:        }
                    234:        /* Make it our controlling tty. */
1.1       deraadt   235: #ifdef TIOCSCTTY
1.6       markus    236:        debug("Setting controlling tty using TIOCSCTTY.");
1.8       markus    237:        /*
                    238:         * We ignore errors from this, because HPSUX defines TIOCSCTTY, but
                    239:         * returns EINVAL with these arguments, and there is absolutely no
                    240:         * documentation.
                    241:         */
1.6       markus    242:        ioctl(*ttyfd, TIOCSCTTY, NULL);
1.1       deraadt   243: #endif /* TIOCSCTTY */
1.6       markus    244:        fd = open(ttyname, O_RDWR);
                    245:        if (fd < 0)
                    246:                error("%.100s: %.100s", ttyname, strerror(errno));
                    247:        else
                    248:                close(fd);
                    249:
                    250:        /* Verify that we now have a controlling tty. */
                    251:        fd = open("/dev/tty", O_WRONLY);
                    252:        if (fd < 0)
                    253:                error("open /dev/tty failed - could not set controlling tty: %.100s",
                    254:                      strerror(errno));
                    255:        else {
                    256:                close(fd);
                    257:        }
1.1       deraadt   258: }
                    259:
                    260: /* Changes the window size associated with the pty. */
                    261:
1.13      markus    262: void
1.6       markus    263: pty_change_window_size(int ptyfd, int row, int col,
                    264:                       int xpixel, int ypixel)
1.1       deraadt   265: {
1.6       markus    266:        struct winsize w;
                    267:        w.ws_row = row;
                    268:        w.ws_col = col;
                    269:        w.ws_xpixel = xpixel;
                    270:        w.ws_ypixel = ypixel;
                    271:        (void) ioctl(ptyfd, TIOCSWINSZ, &w);
1.12      markus    272: }
                    273:
                    274: void
                    275: pty_setowner(struct passwd *pw, const char *ttyname)
                    276: {
                    277:        struct group *grp;
                    278:        gid_t gid;
                    279:        mode_t mode;
                    280:
                    281:        /* Determine the group to make the owner of the tty. */
                    282:        grp = getgrnam("tty");
                    283:        if (grp) {
                    284:                gid = grp->gr_gid;
                    285:                mode = S_IRUSR | S_IWUSR | S_IWGRP;
                    286:        } else {
                    287:                gid = pw->pw_gid;
                    288:                mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
                    289:        }
                    290:
                    291:        /* Change ownership of the tty. */
                    292:        if (chown(ttyname, pw->pw_uid, gid) < 0)
                    293:                fatal("chown(%.100s, %d, %d) failed: %.100s",
                    294:                    ttyname, pw->pw_uid, gid, strerror(errno));
                    295:        if (chmod(ttyname, mode) < 0)
                    296:                fatal("chmod(%.100s, 0%o) failed: %.100s",
                    297:                    ttyname, mode, strerror(errno));
1.1       deraadt   298: }