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

Annotation of src/usr.bin/ssh/sshpty.c, Revision 1.4.2.2

1.1       djm         1: /*
                      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.
                      6:  *
                      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: #include "includes.h"
1.4.2.2 ! miod       15: RCSID("$OpenBSD: sshpty.c,v 1.8 2003/02/03 08:56:16 markus Exp $");
1.1       djm        16:
                     17: #include <util.h>
                     18: #include "sshpty.h"
                     19: #include "log.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:
                     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:  */
                     36:
                     37: int
                     38: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
                     39: {
                     40: #if defined(HAVE_OPENPTY) || defined(BSD4_4)
                     41:        /* openpty(3) exists in OSF/1 and some other os'es */
                     42:        char buf[64];
                     43:        int i;
                     44:
                     45:        i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
                     46:        if (i < 0) {
                     47:                error("openpty: %.100s", strerror(errno));
                     48:                return 0;
                     49:        }
                     50:        strlcpy(namebuf, buf, namebuflen);      /* possible truncation */
                     51:        return 1;
                     52: #else /* HAVE_OPENPTY */
                     53: #ifdef HAVE__GETPTY
                     54:        /*
                     55:         * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
                     56:         * pty's automagically when needed
                     57:         */
                     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:        }
                     65:        strlcpy(namebuf, slave, namebuflen);
                     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;
                     74: #else /* HAVE__GETPTY */
                     75: #ifdef HAVE_DEV_PTMX
                     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:         */
                     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.");
                     99:        strlcpy(namebuf, pts, namebuflen);
                    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:        }
                    109:        /* Push the appropriate streams modules, as described in Solaris pts(7). */
                    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;
                    117: #else /* HAVE_DEV_PTMX */
                    118: #ifdef HAVE_DEV_PTS_AND_PTC
                    119:        /* AIX-style pty code. */
                    120:        const char *name;
                    121:
                    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.");
                    130:        strlcpy(namebuf, name, namebuflen);
                    131:        *ttyfd = open(name, O_RDWR | O_NOCTTY);
                    132:        if (*ttyfd < 0) {
                    133:                error("Could not open pty slave side %.100s: %.100s",
1.4       deraadt   134:                    name, strerror(errno));
1.1       djm       135:                close(*ptyfd);
                    136:                return 0;
                    137:        }
                    138:        return 1;
                    139: #else /* HAVE_DEV_PTS_AND_PTC */
                    140:        /* BSD-style pty code. */
                    141:        char buf[64];
                    142:        int i;
                    143:        const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
                    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;
                    154:                snprintf(namebuf, namebuflen, "/dev/tty%c%c",
                    155:                    ptymajors[i / num_minors], ptyminors[i % num_minors]);
                    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;
                    167: #endif /* HAVE_DEV_PTS_AND_PTC */
                    168: #endif /* HAVE_DEV_PTMX */
                    169: #endif /* HAVE__GETPTY */
                    170: #endif /* HAVE_OPENPTY */
                    171: }
                    172:
                    173: /* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
                    174:
                    175: void
                    176: pty_release(const char *ttyname)
                    177: {
                    178:        if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
                    179:                error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
                    180:        if (chmod(ttyname, (mode_t) 0666) < 0)
                    181:                error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
                    182: }
                    183:
                    184: /* Makes the tty the processes controlling tty and sets it to sane modes. */
                    185:
                    186: void
                    187: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
                    188: {
                    189:        int fd;
                    190:
                    191:        /* First disconnect from the old controlling tty. */
                    192: #ifdef TIOCNOTTY
                    193:        fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
                    194:        if (fd >= 0) {
                    195:                (void) ioctl(fd, TIOCNOTTY, NULL);
                    196:                close(fd);
                    197:        }
                    198: #endif /* TIOCNOTTY */
                    199:        if (setsid() < 0)
                    200:                error("setsid: %.100s", strerror(errno));
                    201:
                    202:        /*
                    203:         * Verify that we are successfully disconnected from the controlling
                    204:         * tty.
                    205:         */
                    206:        fd = open(_PATH_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. */
                    212: #ifdef TIOCSCTTY
                    213:        debug("Setting controlling tty using TIOCSCTTY.");
                    214:        if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
                    215:                error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
                    216: #endif /* TIOCSCTTY */
                    217:        fd = open(ttyname, O_RDWR);
                    218:        if (fd < 0)
                    219:                error("%.100s: %.100s", ttyname, strerror(errno));
                    220:        else
                    221:                close(fd);
                    222:
                    223:        /* Verify that we now have a controlling tty. */
                    224:        fd = open(_PATH_TTY, O_WRONLY);
                    225:        if (fd < 0)
                    226:                error("open /dev/tty failed - could not set controlling tty: %.100s",
1.4       deraadt   227:                    strerror(errno));
1.4.2.1   jason     228:        else
1.1       djm       229:                close(fd);
                    230: }
                    231:
                    232: /* Changes the window size associated with the pty. */
                    233:
                    234: void
                    235: pty_change_window_size(int ptyfd, int row, int col,
1.4       deraadt   236:        int xpixel, int ypixel)
1.1       djm       237: {
                    238:        struct winsize w;
1.4.2.1   jason     239:
1.1       djm       240:        w.ws_row = row;
                    241:        w.ws_col = col;
                    242:        w.ws_xpixel = xpixel;
                    243:        w.ws_ypixel = ypixel;
                    244:        (void) ioctl(ptyfd, TIOCSWINSZ, &w);
                    245: }
                    246:
                    247: void
                    248: pty_setowner(struct passwd *pw, const char *ttyname)
                    249: {
                    250:        struct group *grp;
                    251:        gid_t gid;
                    252:        mode_t mode;
                    253:        struct stat st;
                    254:
                    255:        /* Determine the group to make the owner of the tty. */
                    256:        grp = getgrnam("tty");
                    257:        if (grp) {
                    258:                gid = grp->gr_gid;
                    259:                mode = S_IRUSR | S_IWUSR | S_IWGRP;
                    260:        } else {
                    261:                gid = pw->pw_gid;
                    262:                mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
                    263:        }
                    264:
                    265:        /*
                    266:         * Change owner and mode of the tty as required.
1.3       markus    267:         * Warn but continue if filesystem is read-only and the uids match/
                    268:         * tty is owned by root.
1.1       djm       269:         */
                    270:        if (stat(ttyname, &st))
                    271:                fatal("stat(%.100s) failed: %.100s", ttyname,
                    272:                    strerror(errno));
                    273:
                    274:        if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
                    275:                if (chown(ttyname, pw->pw_uid, gid) < 0) {
1.4       deraadt   276:                        if (errno == EROFS &&
1.4.2.1   jason     277:                            (st.st_uid == pw->pw_uid || st.st_uid == 0))
1.4.2.2 ! miod      278:                                debug("chown(%.100s, %u, %u) failed: %.100s",
1.4.2.1   jason     279:                                    ttyname, (u_int)pw->pw_uid, (u_int)gid,
1.4       deraadt   280:                                    strerror(errno));
1.1       djm       281:                        else
1.4.2.1   jason     282:                                fatal("chown(%.100s, %u, %u) failed: %.100s",
                    283:                                    ttyname, (u_int)pw->pw_uid, (u_int)gid,
1.4       deraadt   284:                                    strerror(errno));
1.1       djm       285:                }
                    286:        }
                    287:
                    288:        if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
                    289:                if (chmod(ttyname, mode) < 0) {
                    290:                        if (errno == EROFS &&
                    291:                            (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
1.4.2.2 ! miod      292:                                debug("chmod(%.100s, 0%o) failed: %.100s",
1.4       deraadt   293:                                    ttyname, mode, strerror(errno));
1.1       djm       294:                        else
                    295:                                fatal("chmod(%.100s, 0%o) failed: %.100s",
1.4       deraadt   296:                                    ttyname, mode, strerror(errno));
1.1       djm       297:                }
                    298:        }
                    299: }