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

Annotation of src/usr.bin/ssh/mux.c, Revision 1.1

1.1     ! djm         1: /* $OpenBSD$ */
        !             2: /*
        !             3:  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17:
        !            18: /* ssh session multiplexing support */
        !            19:
        !            20: #include <sys/types.h>
        !            21: #include <sys/param.h>
        !            22: #include <sys/queue.h>
        !            23: #include <sys/stat.h>
        !            24: #include <sys/socket.h>
        !            25: #include <sys/un.h>
        !            26:
        !            27: #include <errno.h>
        !            28: #include <fcntl.h>
        !            29: #include <signal.h>
        !            30: #include <stdarg.h>
        !            31: #include <stddef.h>
        !            32: #include <stdlib.h>
        !            33: #include <stdio.h>
        !            34: #include <string.h>
        !            35: #include <unistd.h>
        !            36: #include <util.h>
        !            37: #include <paths.h>
        !            38:
        !            39: #include "xmalloc.h"
        !            40: #include "log.h"
        !            41: #include "ssh.h"
        !            42: #include "pathnames.h"
        !            43: #include "misc.h"
        !            44: #include "match.h"
        !            45: #include "buffer.h"
        !            46: #include "channels.h"
        !            47: #include "msg.h"
        !            48: #include "packet.h"
        !            49: #include "monitor_fdpass.h"
        !            50: #include "sshpty.h"
        !            51: #include "key.h"
        !            52: #include "readconf.h"
        !            53: #include "clientloop.h"
        !            54:
        !            55: /* from ssh.c */
        !            56: extern int tty_flag;
        !            57: extern Options options;
        !            58: extern int stdin_null_flag;
        !            59: extern char *host;
        !            60: int subsystem_flag;
        !            61: extern Buffer command;
        !            62:
        !            63: /* fd to control socket */
        !            64: int muxserver_sock = -1;
        !            65:
        !            66: /* Multiplexing control command */
        !            67: u_int muxclient_command = 0;
        !            68:
        !            69: /* Set when signalled. */
        !            70: static volatile sig_atomic_t muxclient_terminate = 0;
        !            71:
        !            72: /* PID of multiplex server */
        !            73: static u_int muxserver_pid = 0;
        !            74:
        !            75:
        !            76: /* ** Multiplexing master support */
        !            77:
        !            78: /* Prepare a mux master to listen on a Unix domain socket. */
        !            79: void
        !            80: muxserver_listen(void)
        !            81: {
        !            82:        struct sockaddr_un addr;
        !            83:        mode_t old_umask;
        !            84:
        !            85:        if (options.control_path == NULL ||
        !            86:            options.control_master == SSHCTL_MASTER_NO)
        !            87:                return;
        !            88:
        !            89:        debug("setting up multiplex master socket");
        !            90:
        !            91:        memset(&addr, '\0', sizeof(addr));
        !            92:        addr.sun_family = AF_UNIX;
        !            93:        addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
        !            94:            strlen(options.control_path) + 1;
        !            95:
        !            96:        if (strlcpy(addr.sun_path, options.control_path,
        !            97:            sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
        !            98:                fatal("ControlPath too long");
        !            99:
        !           100:        if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
        !           101:                fatal("%s socket(): %s", __func__, strerror(errno));
        !           102:
        !           103:        old_umask = umask(0177);
        !           104:        if (bind(muxserver_sock, (struct sockaddr *)&addr, addr.sun_len) == -1) {
        !           105:                muxserver_sock = -1;
        !           106:                if (errno == EINVAL || errno == EADDRINUSE)
        !           107:                        fatal("ControlSocket %s already exists",
        !           108:                            options.control_path);
        !           109:                else
        !           110:                        fatal("%s bind(): %s", __func__, strerror(errno));
        !           111:        }
        !           112:        umask(old_umask);
        !           113:
        !           114:        if (listen(muxserver_sock, 64) == -1)
        !           115:                fatal("%s listen(): %s", __func__, strerror(errno));
        !           116:
        !           117:        set_nonblock(muxserver_sock);
        !           118: }
        !           119:
        !           120: /* Callback on open confirmation in mux master for a mux client session. */
        !           121: static void
        !           122: client_extra_session2_setup(int id, void *arg)
        !           123: {
        !           124:        struct mux_session_confirm_ctx *cctx = arg;
        !           125:        const char *display;
        !           126:        Channel *c;
        !           127:        int i;
        !           128:
        !           129:        if (cctx == NULL)
        !           130:                fatal("%s: cctx == NULL", __func__);
        !           131:        if ((c = channel_lookup(id)) == NULL)
        !           132:                fatal("%s: no channel for id %d", __func__, id);
        !           133:
        !           134:        display = getenv("DISPLAY");
        !           135:        if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
        !           136:                char *proto, *data;
        !           137:                /* Get reasonable local authentication information. */
        !           138:                client_x11_get_proto(display, options.xauth_location,
        !           139:                    options.forward_x11_trusted, &proto, &data);
        !           140:                /* Request forwarding with authentication spoofing. */
        !           141:                debug("Requesting X11 forwarding with authentication spoofing.");
        !           142:                x11_request_forwarding_with_spoofing(id, display, proto, data);
        !           143:                /* XXX wait for reply */
        !           144:        }
        !           145:
        !           146:        if (cctx->want_agent_fwd && options.forward_agent) {
        !           147:                debug("Requesting authentication agent forwarding.");
        !           148:                channel_request_start(id, "auth-agent-req@openssh.com", 0);
        !           149:                packet_send();
        !           150:        }
        !           151:
        !           152:        client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
        !           153:            cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
        !           154:
        !           155:        c->open_confirm_ctx = NULL;
        !           156:        buffer_free(&cctx->cmd);
        !           157:        xfree(cctx->term);
        !           158:        if (cctx->env != NULL) {
        !           159:                for (i = 0; cctx->env[i] != NULL; i++)
        !           160:                        xfree(cctx->env[i]);
        !           161:                xfree(cctx->env);
        !           162:        }
        !           163:        xfree(cctx);
        !           164: }
        !           165:
        !           166: /*
        !           167:  * Accept a connection on the mux master socket and process the
        !           168:  * client's request. Returns flag indicating whether mux master should
        !           169:  * begin graceful close.
        !           170:  */
        !           171: int
        !           172: muxserver_accept_control(void)
        !           173: {
        !           174:        Buffer m;
        !           175:        Channel *c;
        !           176:        int client_fd, new_fd[3], ver, allowed, window, packetmax;
        !           177:        socklen_t addrlen;
        !           178:        struct sockaddr_storage addr;
        !           179:        struct mux_session_confirm_ctx *cctx;
        !           180:        char *cmd;
        !           181:        u_int i, j, len, env_len, mux_command, flags;
        !           182:        uid_t euid;
        !           183:        gid_t egid;
        !           184:        int start_close = 0;
        !           185:
        !           186:        /*
        !           187:         * Accept connection on control socket
        !           188:         */
        !           189:        memset(&addr, 0, sizeof(addr));
        !           190:        addrlen = sizeof(addr);
        !           191:        if ((client_fd = accept(muxserver_sock,
        !           192:            (struct sockaddr*)&addr, &addrlen)) == -1) {
        !           193:                error("%s accept: %s", __func__, strerror(errno));
        !           194:                return 0;
        !           195:        }
        !           196:
        !           197:        if (getpeereid(client_fd, &euid, &egid) < 0) {
        !           198:                error("%s getpeereid failed: %s", __func__, strerror(errno));
        !           199:                close(client_fd);
        !           200:                return 0;
        !           201:        }
        !           202:        if ((euid != 0) && (getuid() != euid)) {
        !           203:                error("control mode uid mismatch: peer euid %u != uid %u",
        !           204:                    (u_int) euid, (u_int) getuid());
        !           205:                close(client_fd);
        !           206:                return 0;
        !           207:        }
        !           208:
        !           209:        /* XXX handle asynchronously */
        !           210:        unset_nonblock(client_fd);
        !           211:
        !           212:        /* Read command */
        !           213:        buffer_init(&m);
        !           214:        if (ssh_msg_recv(client_fd, &m) == -1) {
        !           215:                error("%s: client msg_recv failed", __func__);
        !           216:                close(client_fd);
        !           217:                buffer_free(&m);
        !           218:                return 0;
        !           219:        }
        !           220:        if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
        !           221:                error("%s: wrong client version %d", __func__, ver);
        !           222:                buffer_free(&m);
        !           223:                close(client_fd);
        !           224:                return 0;
        !           225:        }
        !           226:
        !           227:        allowed = 1;
        !           228:        mux_command = buffer_get_int(&m);
        !           229:        flags = buffer_get_int(&m);
        !           230:
        !           231:        buffer_clear(&m);
        !           232:
        !           233:        switch (mux_command) {
        !           234:        case SSHMUX_COMMAND_OPEN:
        !           235:                if (options.control_master == SSHCTL_MASTER_ASK ||
        !           236:                    options.control_master == SSHCTL_MASTER_AUTO_ASK)
        !           237:                        allowed = ask_permission("Allow shared connection "
        !           238:                            "to %s? ", host);
        !           239:                /* continue below */
        !           240:                break;
        !           241:        case SSHMUX_COMMAND_TERMINATE:
        !           242:                if (options.control_master == SSHCTL_MASTER_ASK ||
        !           243:                    options.control_master == SSHCTL_MASTER_AUTO_ASK)
        !           244:                        allowed = ask_permission("Terminate shared connection "
        !           245:                            "to %s? ", host);
        !           246:                if (allowed)
        !           247:                        start_close = 1;
        !           248:                /* FALLTHROUGH */
        !           249:        case SSHMUX_COMMAND_ALIVE_CHECK:
        !           250:                /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
        !           251:                buffer_clear(&m);
        !           252:                buffer_put_int(&m, allowed);
        !           253:                buffer_put_int(&m, getpid());
        !           254:                if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
        !           255:                        error("%s: client msg_send failed", __func__);
        !           256:                        close(client_fd);
        !           257:                        buffer_free(&m);
        !           258:                        return start_close;
        !           259:                }
        !           260:                buffer_free(&m);
        !           261:                close(client_fd);
        !           262:                return start_close;
        !           263:        default:
        !           264:                error("Unsupported command %d", mux_command);
        !           265:                buffer_free(&m);
        !           266:                close(client_fd);
        !           267:                return 0;
        !           268:        }
        !           269:
        !           270:        /* Reply for SSHMUX_COMMAND_OPEN */
        !           271:        buffer_clear(&m);
        !           272:        buffer_put_int(&m, allowed);
        !           273:        buffer_put_int(&m, getpid());
        !           274:        if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
        !           275:                error("%s: client msg_send failed", __func__);
        !           276:                close(client_fd);
        !           277:                buffer_free(&m);
        !           278:                return 0;
        !           279:        }
        !           280:
        !           281:        if (!allowed) {
        !           282:                error("Refused control connection");
        !           283:                close(client_fd);
        !           284:                buffer_free(&m);
        !           285:                return 0;
        !           286:        }
        !           287:
        !           288:        buffer_clear(&m);
        !           289:        if (ssh_msg_recv(client_fd, &m) == -1) {
        !           290:                error("%s: client msg_recv failed", __func__);
        !           291:                close(client_fd);
        !           292:                buffer_free(&m);
        !           293:                return 0;
        !           294:        }
        !           295:        if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
        !           296:                error("%s: wrong client version %d", __func__, ver);
        !           297:                buffer_free(&m);
        !           298:                close(client_fd);
        !           299:                return 0;
        !           300:        }
        !           301:
        !           302:        cctx = xcalloc(1, sizeof(*cctx));
        !           303:        cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
        !           304:        cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
        !           305:        cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
        !           306:        cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
        !           307:        cctx->term = buffer_get_string(&m, &len);
        !           308:
        !           309:        cmd = buffer_get_string(&m, &len);
        !           310:        buffer_init(&cctx->cmd);
        !           311:        buffer_append(&cctx->cmd, cmd, strlen(cmd));
        !           312:
        !           313:        env_len = buffer_get_int(&m);
        !           314:        env_len = MIN(env_len, 4096);
        !           315:        debug3("%s: receiving %d env vars", __func__, env_len);
        !           316:        if (env_len != 0) {
        !           317:                cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env));
        !           318:                for (i = 0; i < env_len; i++)
        !           319:                        cctx->env[i] = buffer_get_string(&m, &len);
        !           320:                cctx->env[i] = NULL;
        !           321:        }
        !           322:
        !           323:        debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
        !           324:            cctx->want_tty, cctx->want_subsys, cmd);
        !           325:        xfree(cmd);
        !           326:
        !           327:        /* Gather fds from client */
        !           328:        for(i = 0; i < 3; i++) {
        !           329:                if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) {
        !           330:                        error("%s: failed to receive fd %d from slave",
        !           331:                            __func__, i);
        !           332:                        for (j = 0; j < i; j++)
        !           333:                                close(new_fd[j]);
        !           334:                        for (j = 0; j < env_len; j++)
        !           335:                                xfree(cctx->env[j]);
        !           336:                        if (env_len > 0)
        !           337:                                xfree(cctx->env);
        !           338:                        xfree(cctx->term);
        !           339:                        buffer_free(&cctx->cmd);
        !           340:                        close(client_fd);
        !           341:                        xfree(cctx);
        !           342:                        return 0;
        !           343:                }
        !           344:        }
        !           345:
        !           346:        debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
        !           347:            new_fd[0], new_fd[1], new_fd[2]);
        !           348:
        !           349:        /* Try to pick up ttymodes from client before it goes raw */
        !           350:        if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
        !           351:                error("%s: tcgetattr: %s", __func__, strerror(errno));
        !           352:
        !           353:        /* This roundtrip is just for synchronisation of ttymodes */
        !           354:        buffer_clear(&m);
        !           355:        if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
        !           356:                error("%s: client msg_send failed", __func__);
        !           357:                close(client_fd);
        !           358:                close(new_fd[0]);
        !           359:                close(new_fd[1]);
        !           360:                close(new_fd[2]);
        !           361:                buffer_free(&m);
        !           362:                xfree(cctx->term);
        !           363:                if (env_len != 0) {
        !           364:                        for (i = 0; i < env_len; i++)
        !           365:                                xfree(cctx->env[i]);
        !           366:                        xfree(cctx->env);
        !           367:                }
        !           368:                return 0;
        !           369:        }
        !           370:        buffer_free(&m);
        !           371:
        !           372:        /* enable nonblocking unless tty */
        !           373:        if (!isatty(new_fd[0]))
        !           374:                set_nonblock(new_fd[0]);
        !           375:        if (!isatty(new_fd[1]))
        !           376:                set_nonblock(new_fd[1]);
        !           377:        if (!isatty(new_fd[2]))
        !           378:                set_nonblock(new_fd[2]);
        !           379:
        !           380:        set_nonblock(client_fd);
        !           381:
        !           382:        window = CHAN_SES_WINDOW_DEFAULT;
        !           383:        packetmax = CHAN_SES_PACKET_DEFAULT;
        !           384:        if (cctx->want_tty) {
        !           385:                window >>= 1;
        !           386:                packetmax >>= 1;
        !           387:        }
        !           388:
        !           389:        c = channel_new("session", SSH_CHANNEL_OPENING,
        !           390:            new_fd[0], new_fd[1], new_fd[2], window, packetmax,
        !           391:            CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
        !           392:
        !           393:        /* XXX */
        !           394:        c->ctl_fd = client_fd;
        !           395:
        !           396:        debug3("%s: channel_new: %d", __func__, c->self);
        !           397:
        !           398:        channel_send_open(c->self);
        !           399:        channel_register_open_confirm(c->self,
        !           400:            client_extra_session2_setup, cctx);
        !           401:        return 0;
        !           402: }
        !           403:
        !           404: /* ** Multiplexing client support */
        !           405:
        !           406: /* Exit signal handler */
        !           407: static void
        !           408: control_client_sighandler(int signo)
        !           409: {
        !           410:        muxclient_terminate = signo;
        !           411: }
        !           412:
        !           413: /*
        !           414:  * Relay signal handler - used to pass some signals from mux client to
        !           415:  * mux master.
        !           416:  */
        !           417: static void
        !           418: control_client_sigrelay(int signo)
        !           419: {
        !           420:        int save_errno = errno;
        !           421:
        !           422:        if (muxserver_pid > 1)
        !           423:                kill(muxserver_pid, signo);
        !           424:
        !           425:        errno = save_errno;
        !           426: }
        !           427:
        !           428: /* Check mux client environment variables before passing them to mux master. */
        !           429: static int
        !           430: env_permitted(char *env)
        !           431: {
        !           432:        int i, ret;
        !           433:        char name[1024], *cp;
        !           434:
        !           435:        if ((cp = strchr(env, '=')) == NULL || cp == env)
        !           436:                return (0);
        !           437:        ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
        !           438:        if (ret <= 0 || (size_t)ret >= sizeof(name))
        !           439:                fatal("env_permitted: name '%.100s...' too long", env);
        !           440:
        !           441:        for (i = 0; i < options.num_send_env; i++)
        !           442:                if (match_pattern(name, options.send_env[i]))
        !           443:                        return (1);
        !           444:
        !           445:        return (0);
        !           446: }
        !           447:
        !           448: /* Multiplex client main loop. */
        !           449: void
        !           450: muxclient(const char *path)
        !           451: {
        !           452:        struct sockaddr_un addr;
        !           453:        int i, r, fd, sock, exitval[2], num_env;
        !           454:        Buffer m;
        !           455:        char *term;
        !           456:        extern char **environ;
        !           457:        u_int  flags;
        !           458:
        !           459:        if (muxclient_command == 0)
        !           460:                muxclient_command = SSHMUX_COMMAND_OPEN;
        !           461:
        !           462:        switch (options.control_master) {
        !           463:        case SSHCTL_MASTER_AUTO:
        !           464:        case SSHCTL_MASTER_AUTO_ASK:
        !           465:                debug("auto-mux: Trying existing master");
        !           466:                /* FALLTHROUGH */
        !           467:        case SSHCTL_MASTER_NO:
        !           468:                break;
        !           469:        default:
        !           470:                return;
        !           471:        }
        !           472:
        !           473:        memset(&addr, '\0', sizeof(addr));
        !           474:        addr.sun_family = AF_UNIX;
        !           475:        addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
        !           476:            strlen(path) + 1;
        !           477:
        !           478:        if (strlcpy(addr.sun_path, path,
        !           479:            sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
        !           480:                fatal("ControlPath too long");
        !           481:
        !           482:        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
        !           483:                fatal("%s socket(): %s", __func__, strerror(errno));
        !           484:
        !           485:        if (connect(sock, (struct sockaddr *)&addr, addr.sun_len) == -1) {
        !           486:                if (muxclient_command != SSHMUX_COMMAND_OPEN) {
        !           487:                        fatal("Control socket connect(%.100s): %s", path,
        !           488:                            strerror(errno));
        !           489:                }
        !           490:                if (errno == ENOENT)
        !           491:                        debug("Control socket \"%.100s\" does not exist", path);
        !           492:                else {
        !           493:                        error("Control socket connect(%.100s): %s", path,
        !           494:                            strerror(errno));
        !           495:                }
        !           496:                close(sock);
        !           497:                return;
        !           498:        }
        !           499:
        !           500:        if (stdin_null_flag) {
        !           501:                if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
        !           502:                        fatal("open(/dev/null): %s", strerror(errno));
        !           503:                if (dup2(fd, STDIN_FILENO) == -1)
        !           504:                        fatal("dup2: %s", strerror(errno));
        !           505:                if (fd > STDERR_FILENO)
        !           506:                        close(fd);
        !           507:        }
        !           508:
        !           509:        term = getenv("TERM");
        !           510:
        !           511:        flags = 0;
        !           512:        if (tty_flag)
        !           513:                flags |= SSHMUX_FLAG_TTY;
        !           514:        if (subsystem_flag)
        !           515:                flags |= SSHMUX_FLAG_SUBSYS;
        !           516:        if (options.forward_x11)
        !           517:                flags |= SSHMUX_FLAG_X11_FWD;
        !           518:        if (options.forward_agent)
        !           519:                flags |= SSHMUX_FLAG_AGENT_FWD;
        !           520:
        !           521:        signal(SIGPIPE, SIG_IGN);
        !           522:
        !           523:        buffer_init(&m);
        !           524:
        !           525:        /* Send our command to server */
        !           526:        buffer_put_int(&m, muxclient_command);
        !           527:        buffer_put_int(&m, flags);
        !           528:        if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
        !           529:                fatal("%s: msg_send", __func__);
        !           530:        buffer_clear(&m);
        !           531:
        !           532:        /* Get authorisation status and PID of controlee */
        !           533:        if (ssh_msg_recv(sock, &m) == -1)
        !           534:                fatal("%s: msg_recv", __func__);
        !           535:        if (buffer_get_char(&m) != SSHMUX_VER)
        !           536:                fatal("%s: wrong version", __func__);
        !           537:        if (buffer_get_int(&m) != 1)
        !           538:                fatal("Connection to master denied");
        !           539:        muxserver_pid = buffer_get_int(&m);
        !           540:
        !           541:        buffer_clear(&m);
        !           542:
        !           543:        switch (muxclient_command) {
        !           544:        case SSHMUX_COMMAND_ALIVE_CHECK:
        !           545:                fprintf(stderr, "Master running (pid=%d)\r\n",
        !           546:                    muxserver_pid);
        !           547:                exit(0);
        !           548:        case SSHMUX_COMMAND_TERMINATE:
        !           549:                fprintf(stderr, "Exit request sent.\r\n");
        !           550:                exit(0);
        !           551:        case SSHMUX_COMMAND_OPEN:
        !           552:                /* continue below */
        !           553:                break;
        !           554:        default:
        !           555:                fatal("silly muxclient_command %d", muxclient_command);
        !           556:        }
        !           557:
        !           558:        /* SSHMUX_COMMAND_OPEN */
        !           559:        buffer_put_cstring(&m, term ? term : "");
        !           560:        buffer_append(&command, "\0", 1);
        !           561:        buffer_put_cstring(&m, buffer_ptr(&command));
        !           562:
        !           563:        if (options.num_send_env == 0 || environ == NULL) {
        !           564:                buffer_put_int(&m, 0);
        !           565:        } else {
        !           566:                /* Pass environment */
        !           567:                num_env = 0;
        !           568:                for (i = 0; environ[i] != NULL; i++)
        !           569:                        if (env_permitted(environ[i]))
        !           570:                                num_env++; /* Count */
        !           571:
        !           572:                buffer_put_int(&m, num_env);
        !           573:
        !           574:                for (i = 0; environ[i] != NULL && num_env >= 0; i++)
        !           575:                        if (env_permitted(environ[i])) {
        !           576:                                num_env--;
        !           577:                                buffer_put_cstring(&m, environ[i]);
        !           578:                        }
        !           579:        }
        !           580:
        !           581:        if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
        !           582:                fatal("%s: msg_send", __func__);
        !           583:
        !           584:        if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
        !           585:            mm_send_fd(sock, STDOUT_FILENO) == -1 ||
        !           586:            mm_send_fd(sock, STDERR_FILENO) == -1)
        !           587:                fatal("%s: send fds failed", __func__);
        !           588:
        !           589:        /* Wait for reply, so master has a chance to gather ttymodes */
        !           590:        buffer_clear(&m);
        !           591:        if (ssh_msg_recv(sock, &m) == -1)
        !           592:                fatal("%s: msg_recv", __func__);
        !           593:        if (buffer_get_char(&m) != SSHMUX_VER)
        !           594:                fatal("%s: wrong version", __func__);
        !           595:        buffer_free(&m);
        !           596:
        !           597:        signal(SIGHUP, control_client_sighandler);
        !           598:        signal(SIGINT, control_client_sighandler);
        !           599:        signal(SIGTERM, control_client_sighandler);
        !           600:        signal(SIGWINCH, control_client_sigrelay);
        !           601:
        !           602:        if (tty_flag)
        !           603:                enter_raw_mode();
        !           604:
        !           605:        /*
        !           606:         * Stick around until the controlee closes the client_fd.
        !           607:         * Before it does, it is expected to write this process' exit
        !           608:         * value (one int). This process must read the value and wait for
        !           609:         * the closure of the client_fd; if this one closes early, the
        !           610:         * multiplex master will terminate early too (possibly losing data).
        !           611:         */
        !           612:        exitval[0] = 0;
        !           613:        for (i = 0; !muxclient_terminate && i < (int)sizeof(exitval);) {
        !           614:                r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
        !           615:                if (r == 0) {
        !           616:                        debug2("Received EOF from master");
        !           617:                        break;
        !           618:                }
        !           619:                if (r == -1) {
        !           620:                        if (errno == EINTR)
        !           621:                                continue;
        !           622:                        fatal("%s: read %s", __func__, strerror(errno));
        !           623:                }
        !           624:                i += r;
        !           625:        }
        !           626:
        !           627:        close(sock);
        !           628:        leave_raw_mode();
        !           629:        if (i > (int)sizeof(int))
        !           630:                fatal("%s: master returned too much data (%d > %lu)",
        !           631:                    __func__, i, sizeof(int));
        !           632:        if (muxclient_terminate) {
        !           633:                debug2("Exiting on signal %d", muxclient_terminate);
        !           634:                exitval[0] = 255;
        !           635:        } else if (i < (int)sizeof(int)) {
        !           636:                debug2("Control master terminated unexpectedly");
        !           637:                exitval[0] = 255;
        !           638:        } else
        !           639:                debug2("Received exit status from master %d", exitval[0]);
        !           640:
        !           641:        if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
        !           642:                fprintf(stderr, "Shared connection to %s closed.\r\n", host);
        !           643:
        !           644:        exit(exitval[0]);
        !           645: }