]> andersk Git - openssh.git/blobdiff - clientloop.c
- djm@cvs.openbsd.org 2008/06/12 21:06:25
[openssh.git] / clientloop.c
index b45e7298a802ff2e8aefb2bfae549cb214be7a4e..6dc870881b54af351777efb829c20af5b7d77371 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.199 2008/06/12 21:06:25 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -147,8 +147,8 @@ static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
 static int escape_char1;       /* Escape character. (proto1 only) */
 static int escape_pending1;    /* Last character was an escape (proto1 only) */
 static int last_was_cr;                /* Last character was a newline. */
-static int exit_status;                /* Used to store the exit status of the command. */
-static int stdin_eof;          /* EOF has been encountered on standard error. */
+static int exit_status;                /* Used to store the command exit status. */
+static int stdin_eof;          /* EOF has been encountered on stderr. */
 static Buffer stdin_buffer;    /* Buffer for stdin data. */
 static Buffer stdout_buffer;   /* Buffer for stdout data. */
 static Buffer stderr_buffer;   /* Buffer for stderr data. */
@@ -174,6 +174,17 @@ struct channel_reply_ctx {
        int id, do_close;
 };
 
+/* Global request success/failure callbacks */
+struct global_confirm {
+       TAILQ_ENTRY(global_confirm) entry;
+       global_confirm_cb *cb;
+       void *ctx;
+       int ref_count;
+};
+TAILQ_HEAD(global_confirms, global_confirm);
+static struct global_confirms global_confirms =
+    TAILQ_HEAD_INITIALIZER(global_confirms);
+
 /*XXX*/
 extern Kex *xxx_kex;
 
@@ -381,7 +392,10 @@ client_check_initial_eof_on_stdin(void)
                /* Check for immediate EOF on stdin. */
                len = read(fileno(stdin), buf, 1);
                if (len == 0) {
-                       /* EOF.  Record that we have seen it and send EOF to server. */
+                       /*
+                        * EOF.  Record that we have seen it and send
+                        * EOF to server.
+                        */
                        debug("Sending eof.");
                        stdin_eof = 1;
                        packet_start(SSH_CMSG_EOF);
@@ -468,8 +482,19 @@ client_check_window_change(void)
 static void
 client_global_request_reply(int type, u_int32_t seq, void *ctxt)
 {
+       struct global_confirm *gc;
+
+       if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
+               return;
+       if (gc->cb != NULL)
+               gc->cb(type, seq, gc->ctx);
+       if (--gc->ref_count <= 0) {
+               TAILQ_REMOVE(&global_confirms, gc, entry);
+               bzero(gc, sizeof(*gc));
+               xfree(gc);
+       }
+
        keep_alive_timeouts = 0;
-       client_global_request_reply_fwd(type, seq, ctxt);
 }
 
 static void
@@ -483,6 +508,8 @@ server_alive_check(void)
        packet_put_cstring("keepalive@openssh.com");
        packet_put_char(1);     /* boolean: want reply */
        packet_send();
+       /* Insert an empty placeholder to maintain ordering */
+       client_register_global_confirm(NULL, NULL);
 }
 
 /*
@@ -577,9 +604,11 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
 {
        /* Flush stdout and stderr buffers. */
        if (buffer_len(bout) > 0)
-               atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout));
+               atomicio(vwrite, fileno(stdout), buffer_ptr(bout),
+                   buffer_len(bout));
        if (buffer_len(berr) > 0)
-               atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr));
+               atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
+                   buffer_len(berr));
 
        leave_raw_mode();
 
@@ -619,9 +648,13 @@ client_process_net_input(fd_set *readset)
                /* Read as much as possible. */
                len = read(connection_in, buf, sizeof(buf));
                if (len == 0) {
-                       /* Received EOF.  The remote host has closed the connection. */
-                       snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
-                                host);
+                       /*
+                        * Received EOF.  The remote host has closed the
+                        * connection.
+                        */
+                       snprintf(buf, sizeof buf,
+                           "Connection to %.300s closed by remote host.\r\n",
+                           host);
                        buffer_append(&stderr_buffer, buf, strlen(buf));
                        quit_pending = 1;
                        return;
@@ -634,9 +667,13 @@ client_process_net_input(fd_set *readset)
                        len = 0;
 
                if (len < 0) {
-                       /* An error has encountered.  Perhaps there is a network problem. */
-                       snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
-                                host, strerror(errno));
+                       /*
+                        * An error has encountered.  Perhaps there is a
+                        * network problem.
+                        */
+                       snprintf(buf, sizeof buf,
+                           "Read from remote host %.300s: %.100s\r\n",
+                           host, strerror(errno));
                        buffer_append(&stderr_buffer, buf, strlen(buf));
                        quit_pending = 1;
                        return;
@@ -702,6 +739,27 @@ client_expect_confirm(int id, const char *request, int do_close)
            client_abandon_status_confirm, cr);
 }
 
+void
+client_register_global_confirm(global_confirm_cb *cb, void *ctx)
+{
+       struct global_confirm *gc, *first_gc;
+
+       /* Coalesce identical callbacks */
+       first_gc = TAILQ_LAST(&global_confirms, global_confirms);
+       if (first_gc && first_gc->cb == cb && first_gc->ctx == ctx) {
+               if (++first_gc->ref_count >= INT_MAX)
+                       fatal("%s: first_gc->ref_count = %d",
+                           __func__, first_gc->ref_count);
+               return;
+       }
+
+       gc = xmalloc(sizeof(*gc));
+       gc->cb = cb;
+       gc->ctx = ctx;
+       gc->ref_count = 1;
+       TAILQ_INSERT_TAIL(&global_confirms, gc, entry);
+}
+
 static void
 process_cmdline(void)
 {
@@ -887,8 +945,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
                                            strlen(string));
                                        continue;
                                }
-                               /* Suspend the program. */
-                               /* Print a message to that effect to the user. */
+                               /* Suspend the program. Inform the user */
                                snprintf(string, sizeof string,
                                    "%c^Z [suspend ssh]\r\n", escape_char);
                                buffer_append(berr, string, strlen(string));
@@ -915,7 +972,8 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
                        case 'R':
                                if (compat20) {
                                        if (datafellows & SSH_BUG_NOREKEY)
-                                               logit("Server does not support re-keying");
+                                               logit("Server does not "
+                                                   "support re-keying");
                                        else
                                                need_rekeying = 1;
                                }
@@ -925,8 +983,9 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
                                if (c && c->ctl_fd != -1)
                                        goto noescape;
                                /*
-                                * Detach the program (continue to serve connections,
-                                * but put in background and no more new connections).
+                                * Detach the program (continue to serve
+                                * connections, but put in background and no
+                                * more new connections).
                                 */
                                /* Restore tty modes. */
                                leave_raw_mode();
@@ -955,9 +1014,9 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
                                        return -1;
                                } else if (!stdin_eof) {
                                        /*
-                                        * Sending SSH_CMSG_EOF alone does not always appear
-                                        * to be enough.  So we try to send an EOF character
-                                        * first.
+                                        * Sending SSH_CMSG_EOF alone does not
+                                        * always appear to be enough.  So we
+                                        * try to send an EOF character first.
                                         */
                                        packet_start(SSH_CMSG_STDIN_DATA);
                                        packet_put_string("\004", 1);
@@ -1036,11 +1095,14 @@ Supported escape sequences:\r\n\
                        }
                } else {
                        /*
-                        * The previous character was not an escape char. Check if this
-                        * is an escape.
+                        * The previous character was not an escape char.
+                        * Check if this is an escape.
                         */
                        if (last_was_cr && ch == escape_char) {
-                               /* It is. Set the flag and continue to next character. */
+                               /*
+                                * It is. Set the flag and continue to
+                                * next character.
+                                */
                                *escape_pendingp = 1;
                                continue;
                        }
@@ -1076,7 +1138,8 @@ client_process_input(fd_set *readset)
                         * if it was an error condition.
                         */
                        if (len < 0) {
-                               snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
+                               snprintf(buf, sizeof buf, "read: %.100s\r\n",
+                                   strerror(errno));
                                buffer_append(&stderr_buffer, buf, strlen(buf));
                        }
                        /* Mark that we have seen EOF. */
@@ -1100,8 +1163,9 @@ client_process_input(fd_set *readset)
                        buffer_append(&stdin_buffer, buf, len);
                } else {
                        /*
-                        * Normal, successful read.  But we have an escape character
-                        * and have to process the characters one by one.
+                        * Normal, successful read.  But we have an escape
+                        * character and have to process the characters one
+                        * by one.
                         */
                        if (process_escapes(NULL, &stdin_buffer,
                            &stdout_buffer, &stderr_buffer, buf, len) == -1)
@@ -1129,7 +1193,8 @@ client_process_output(fd_set *writeset)
                                 * An error or EOF was encountered.  Put an
                                 * error message to stderr buffer.
                                 */
-                               snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
+                               snprintf(buf, sizeof buf,
+                                   "write stdout: %.50s\r\n", strerror(errno));
                                buffer_append(&stderr_buffer, buf, strlen(buf));
                                quit_pending = 1;
                                return;
@@ -1148,7 +1213,10 @@ client_process_output(fd_set *writeset)
                        if (errno == EINTR || errno == EAGAIN)
                                len = 0;
                        else {
-                               /* EOF or error, but can't even print error message. */
+                               /*
+                                * EOF or error, but can't even print
+                                * error message.
+                                */
                                quit_pending = 1;
                                return;
                        }
@@ -1174,7 +1242,8 @@ client_process_output(fd_set *writeset)
 static void
 client_process_buffered_input_packets(void)
 {
-       dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
+       dispatch_run(DISPATCH_NONBLOCK, &quit_pending,
+           compat20 ? xxx_kex : NULL);
 }
 
 /* scan buf[] for '~' before sending data to the peer */
@@ -1191,6 +1260,13 @@ client_new_escape_filter_ctx(int escape_char)
        return (void *)ret;
 }
 
+/* Free the escape filter context on channel free */
+void
+client_filter_cleanup(int cid, void *ctx)
+{
+       xfree(ctx);
+}
+
 int
 client_simple_escape_filter(Channel *c, char *buf, int len)
 {
@@ -1288,6 +1364,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                if (escape_char_arg != SSH_ESCAPECHAR_NONE)
                        channel_register_filter(session_ident,
                            client_simple_escape_filter, NULL,
+                           client_filter_cleanup,
                            client_new_escape_filter_ctx(escape_char_arg));
                if (session_ident != -1)
                        channel_register_cleanup(session_ident,
@@ -1378,7 +1455,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                        client_process_output(writeset);
                }
 
-               /* Send as much buffered packet data as possible to the sender. */
+               /*
+                * Send as much buffered packet data as possible to the
+                * sender.
+                */
                if (FD_ISSET(connection_out, writeset))
                        packet_write_poll();
        }
@@ -1423,7 +1503,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
         * that the connection has been closed.
         */
        if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
-               snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
+               snprintf(buf, sizeof buf,
+                   "Connection to %.64s closed.\r\n", host);
                buffer_append(&stderr_buffer, buf, strlen(buf));
        }
 
@@ -1459,8 +1540,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 
        /* Report bytes transferred, and transfer rates. */
        total_time = get_current_time() - start_time;
-       debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
-           stdin_bytes, stdout_bytes, stderr_bytes, total_time);
+       debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f "
+           "seconds", stdin_bytes, stdout_bytes, stderr_bytes, total_time);
        if (total_time > 0)
                debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
                    stdin_bytes / total_time, stdout_bytes / total_time,
@@ -1586,7 +1667,8 @@ client_request_x11(const char *request_type, int rchan)
 
        if (!options.forward_x11) {
                error("Warning: ssh server tried X11 forwarding.");
-               error("Warning: this is probably a break-in attempt by a malicious server.");
+               error("Warning: this is probably a break-in attempt by a "
+                   "malicious server.");
                return NULL;
        }
        originator = packet_get_string(NULL);
@@ -1619,7 +1701,8 @@ client_request_agent(const char *request_type, int rchan)
 
        if (!options.forward_agent) {
                error("Warning: ssh server tried agent forwarding.");
-               error("Warning: this is probably a break-in attempt by a malicious server.");
+               error("Warning: this is probably a break-in attempt by a "
+                   "malicious server.");
                return NULL;
        }
        sock = ssh_get_authentication_socket();
@@ -1662,7 +1745,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
 #if defined(SSH_TUN_FILTER)
        if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
                channel_register_filter(c->self, sys_tun_infilter,
-                   sys_tun_outfilter);
+                   sys_tun_outfilter, NULL, NULL);
 #endif
 
        packet_start(SSH2_MSG_CHANNEL_OPEN);
@@ -1745,7 +1828,8 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
        if (id == -1) {
                error("client_input_channel_req: request for channel -1");
        } else if ((c = channel_lookup(id)) == NULL) {
-               error("client_input_channel_req: channel %d: unknown channel", id);
+               error("client_input_channel_req: channel %d: "
+                   "unknown channel", id);
        } else if (strcmp(rtype, "eow@openssh.com") == 0) {
                packet_check_eom();
                chan_rcvd_eow(c);
@@ -1911,6 +1995,7 @@ client_init_dispatch_20(void)
        dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply);
        dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
 }
+
 static void
 client_init_dispatch_13(void)
 {
@@ -1930,6 +2015,7 @@ client_init_dispatch_13(void)
        dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
            &x11_input_open : &deny_input_open);
 }
+
 static void
 client_init_dispatch_15(void)
 {
@@ -1937,6 +2023,7 @@ client_init_dispatch_15(void)
        dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
        dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
 }
+
 static void
 client_init_dispatch(void)
 {
This page took 0.052075 seconds and 4 git commands to generate.