summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/serverloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/serverloop.c')
-rw-r--r--crypto/openssh/serverloop.c229
1 files changed, 188 insertions, 41 deletions
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
index 2f8e3a0..306ac36 100644
--- a/crypto/openssh/serverloop.c
+++ b/crypto/openssh/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.170 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.178 2015/02/20 22:17:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -37,8 +37,8 @@
#include "includes.h"
+#include <sys/param.h> /* MIN MAX */
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/wait.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TIME_H
@@ -61,6 +61,7 @@
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "canohost.h"
#include "sshpty.h"
@@ -77,13 +78,12 @@
#include "dispatch.h"
#include "auth-options.h"
#include "serverloop.h"
-#include "misc.h"
#include "roaming.h"
+#include "ssherr.h"
extern ServerOptions options;
/* XXX */
-extern Kex *xxx_kex;
extern Authctxt *the_authctxt;
extern int use_privsep;
@@ -545,7 +545,7 @@ drain_output(void)
static void
process_buffered_input_packets(void)
{
- dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
+ dispatch_run(DISPATCH_NONBLOCK, NULL, active_state);
}
/*
@@ -851,7 +851,7 @@ server_loop2(Authctxt *authctxt)
for (;;) {
process_buffered_input_packets();
- rekeying = (xxx_kex != NULL && !xxx_kex->done);
+ rekeying = (active_state->kex != NULL && !active_state->kex->done);
if (!rekeying && packet_not_very_much_data_to_write())
channel_output_poll();
@@ -874,8 +874,8 @@ server_loop2(Authctxt *authctxt)
channel_after_select(readset, writeset);
if (packet_need_rekeying()) {
debug("need rekeying");
- xxx_kex->done = 0;
- kex_send_kexinit(xxx_kex);
+ active_state->kex->done = 0;
+ kex_send_kexinit(active_state);
}
}
process_input(readset);
@@ -895,7 +895,7 @@ server_loop2(Authctxt *authctxt)
session_destroy_all(NULL);
}
-static void
+static int
server_input_keep_alive(int type, u_int32_t seq, void *ctxt)
{
debug("Got %d/%u for keepalive", type, seq);
@@ -905,9 +905,10 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt)
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
packet_set_alive_timeouts(0);
+ return 0;
}
-static void
+static int
server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
{
char *data;
@@ -916,15 +917,16 @@ server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
/* Stdin data from the client. Append it to the buffer. */
/* Ignore any data if the client has closed stdin. */
if (fdin == -1)
- return;
+ return 0;
data = packet_get_string(&data_len);
packet_check_eom();
buffer_append(&stdin_buffer, data, data_len);
explicit_bzero(data, data_len);
free(data);
+ return 0;
}
-static void
+static int
server_input_eof(int type, u_int32_t seq, void *ctxt)
{
/*
@@ -935,9 +937,10 @@ server_input_eof(int type, u_int32_t seq, void *ctxt)
debug("EOF received for stdin.");
packet_check_eom();
stdin_eof = 1;
+ return 0;
}
-static void
+static int
server_input_window_size(int type, u_int32_t seq, void *ctxt)
{
u_int row = packet_get_int();
@@ -949,6 +952,7 @@ server_input_window_size(int type, u_int32_t seq, void *ctxt)
packet_check_eom();
if (fdin != -1)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
+ return 0;
}
static Channel *
@@ -970,7 +974,7 @@ server_request_direct_tcpip(void)
/* XXX fine grained permissions */
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
!no_port_forwarding_flag) {
- c = channel_connect_to(target, target_port,
+ c = channel_connect_to_port(target, target_port,
"direct-tcpip", "direct-tcpip");
} else {
logit("refused local port forward: "
@@ -985,6 +989,38 @@ server_request_direct_tcpip(void)
}
static Channel *
+server_request_direct_streamlocal(void)
+{
+ Channel *c = NULL;
+ char *target, *originator;
+ u_short originator_port;
+
+ target = packet_get_string(NULL);
+ originator = packet_get_string(NULL);
+ originator_port = packet_get_int();
+ packet_check_eom();
+
+ debug("server_request_direct_streamlocal: originator %s port %d, target %s",
+ originator, originator_port, target);
+
+ /* XXX fine grained permissions */
+ if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
+ !no_port_forwarding_flag) {
+ c = channel_connect_to_path(target,
+ "direct-streamlocal@openssh.com", "direct-streamlocal");
+ } else {
+ logit("refused streamlocal port forward: "
+ "originator %s port %d, target %s",
+ originator, originator_port, target);
+ }
+
+ free(originator);
+ free(target);
+
+ return c;
+}
+
+static Channel *
server_request_tun(void)
{
Channel *c = NULL;
@@ -1061,7 +1097,7 @@ server_request_session(void)
return c;
}
-static void
+static int
server_input_channel_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
@@ -1081,6 +1117,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
c = server_request_session();
} else if (strcmp(ctype, "direct-tcpip") == 0) {
c = server_request_direct_tcpip();
+ } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
+ c = server_request_direct_streamlocal();
} else if (strcmp(ctype, "tun@openssh.com") == 0) {
c = server_request_tun();
}
@@ -1109,14 +1147,86 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
packet_send();
}
free(ctype);
+ return 0;
}
-static void
+static int
+server_input_hostkeys_prove(struct sshbuf **respp)
+{
+ struct ssh *ssh = active_state; /* XXX */
+ struct sshbuf *resp = NULL;
+ struct sshbuf *sigbuf = NULL;
+ struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
+ int r, ndx, success = 0;
+ const u_char *blob;
+ u_char *sig = 0;
+ size_t blen, slen;
+
+ if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new", __func__);
+
+ while (ssh_packet_remaining(ssh) > 0) {
+ sshkey_free(key);
+ key = NULL;
+ if ((r = sshpkt_get_string_direct(ssh, &blob, &blen)) != 0 ||
+ (r = sshkey_from_blob(blob, blen, &key)) != 0) {
+ error("%s: couldn't parse key: %s",
+ __func__, ssh_err(r));
+ goto out;
+ }
+ /*
+ * Better check that this is actually one of our hostkeys
+ * before attempting to sign anything with it.
+ */
+ if ((ndx = ssh->kex->host_key_index(key, 1, ssh)) == -1) {
+ error("%s: unknown host %s key",
+ __func__, sshkey_type(key));
+ goto out;
+ }
+ /*
+ * XXX refactor: make kex->sign just use an index rather
+ * than passing in public and private keys
+ */
+ if ((key_prv = get_hostkey_by_index(ndx)) == NULL &&
+ (key_pub = get_hostkey_public_by_index(ndx, ssh)) == NULL) {
+ error("%s: can't retrieve hostkey %d", __func__, ndx);
+ goto out;
+ }
+ sshbuf_reset(sigbuf);
+ free(sig);
+ sig = NULL;
+ if ((r = sshbuf_put_cstring(sigbuf,
+ "hostkeys-prove-00@openssh.com")) != 0 ||
+ (r = sshbuf_put_string(sigbuf,
+ ssh->kex->session_id, ssh->kex->session_id_len)) != 0 ||
+ (r = sshkey_puts(key, sigbuf)) != 0 ||
+ (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen,
+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), 0)) != 0 ||
+ (r = sshbuf_put_string(resp, sig, slen)) != 0) {
+ error("%s: couldn't prepare signature: %s",
+ __func__, ssh_err(r));
+ goto out;
+ }
+ }
+ /* Success */
+ *respp = resp;
+ resp = NULL; /* don't free it */
+ success = 1;
+ out:
+ free(sig);
+ sshbuf_free(resp);
+ sshbuf_free(sigbuf);
+ sshkey_free(key);
+ return success;
+}
+
+static int
server_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
- int success = 0, allocated_listen_port = 0;
+ int r, success = 0, allocated_listen_port = 0;
+ struct sshbuf *resp = NULL;
rtype = packet_get_string(NULL);
want_reply = packet_get_char();
@@ -1125,63 +1235,99 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
/* -R style forwarding */
if (strcmp(rtype, "tcpip-forward") == 0) {
struct passwd *pw;
- char *listen_address;
- u_short listen_port;
+ struct Forward fwd;
pw = the_authctxt->pw;
if (pw == NULL || !the_authctxt->valid)
fatal("server_input_global_request: no/invalid user");
- listen_address = packet_get_string(NULL);
- listen_port = (u_short)packet_get_int();
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_host = packet_get_string(NULL);
+ fwd.listen_port = (u_short)packet_get_int();
debug("server_input_global_request: tcpip-forward listen %s port %d",
- listen_address, listen_port);
+ fwd.listen_host, fwd.listen_port);
/* check permissions */
if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
no_port_forwarding_flag ||
- (!want_reply && listen_port == 0)
+ (!want_reply && fwd.listen_port == 0)
#ifndef NO_IPPORT_RESERVED_CONCEPT
- || (listen_port != 0 && listen_port < IPPORT_RESERVED &&
- pw->pw_uid != 0)
+ || (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED &&
+ pw->pw_uid != 0)
#endif
) {
success = 0;
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
- success = channel_setup_remote_fwd_listener(
- listen_address, listen_port,
- &allocated_listen_port, options.gateway_ports);
+ success = channel_setup_remote_fwd_listener(&fwd,
+ &allocated_listen_port, &options.fwd_opts);
}
- free(listen_address);
+ free(fwd.listen_host);
+ if ((resp = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new", __func__);
+ if ((r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
+ fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r));
} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
- char *cancel_address;
- u_short cancel_port;
+ struct Forward fwd;
- cancel_address = packet_get_string(NULL);
- cancel_port = (u_short)packet_get_int();
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_host = packet_get_string(NULL);
+ fwd.listen_port = (u_short)packet_get_int();
debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
- cancel_address, cancel_port);
+ fwd.listen_host, fwd.listen_port);
+
+ success = channel_cancel_rport_listener(&fwd);
+ free(fwd.listen_host);
+ } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
+ struct Forward fwd;
+
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_path = packet_get_string(NULL);
+ debug("server_input_global_request: streamlocal-forward listen path %s",
+ fwd.listen_path);
- success = channel_cancel_rport_listener(cancel_address,
- cancel_port);
- free(cancel_address);
+ /* check permissions */
+ if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
+ || no_port_forwarding_flag) {
+ success = 0;
+ packet_send_debug("Server has disabled port forwarding.");
+ } else {
+ /* Start listening on the socket */
+ success = channel_setup_remote_fwd_listener(
+ &fwd, NULL, &options.fwd_opts);
+ }
+ free(fwd.listen_path);
+ } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
+ struct Forward fwd;
+
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_path = packet_get_string(NULL);
+ debug("%s: cancel-streamlocal-forward path %s", __func__,
+ fwd.listen_path);
+
+ success = channel_cancel_rport_listener(&fwd);
+ free(fwd.listen_path);
} else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
no_more_sessions = 1;
success = 1;
+ } else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) {
+ success = server_input_hostkeys_prove(&resp);
}
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
- if (success && allocated_listen_port > 0)
- packet_put_int(allocated_listen_port);
+ if (success && resp != NULL)
+ ssh_packet_put_raw(active_state, sshbuf_ptr(resp),
+ sshbuf_len(resp));
packet_send();
packet_write_wait();
}
free(rtype);
+ sshbuf_free(resp);
+ return 0;
}
-static void
+static int
server_input_channel_req(int type, u_int32_t seq, void *ctxt)
{
Channel *c;
@@ -1204,13 +1350,14 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
} else if ((c->type == SSH_CHANNEL_LARVAL ||
c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
success = session_input_channel_req(c, rtype);
- if (reply) {
+ if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
free(rtype);
+ return 0;
}
static void
OpenPOWER on IntegriCloud