-/* $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
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. */
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;
/* 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);
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
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);
}
/*
{
/* 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();
/* 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;
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;
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)
{
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));
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;
}
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();
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);
}
} 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;
}
* 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. */
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)
* 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;
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;
}
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 */
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)
{
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,
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();
}
* 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));
}
/* 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,
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);
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();
#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);
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);
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)
{
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
&x11_input_open : &deny_input_open);
}
+
static void
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)
{