diff options
Diffstat (limited to 'crypto/openssh/serverloop.c')
-rw-r--r-- | crypto/openssh/serverloop.c | 122 |
1 files changed, 104 insertions, 18 deletions
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index a24a06fb576f..f45baa576fae 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.172 2014/07/15 15:54:14 millert 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 @@ -38,8 +38,8 @@ #include "includes.h" __RCSID("$FreeBSD$"); +#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 @@ -80,11 +80,11 @@ __RCSID("$FreeBSD$"); #include "auth-options.h" #include "serverloop.h" #include "roaming.h" +#include "ssherr.h" extern ServerOptions options; /* XXX */ -extern Kex *xxx_kex; extern Authctxt *the_authctxt; extern int use_privsep; @@ -546,7 +546,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); } /* @@ -852,7 +852,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(); @@ -875,8 +875,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); @@ -896,7 +896,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); @@ -906,9 +906,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; @@ -917,15 +918,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) { /* @@ -936,9 +938,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(); @@ -950,6 +953,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 * @@ -1094,7 +1098,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; @@ -1144,14 +1148,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(); @@ -1188,6 +1264,10 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) &allocated_listen_port, &options.fwd_opts); } 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) { struct Forward fwd; @@ -1231,19 +1311,24 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) } 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; @@ -1273,6 +1358,7 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt) packet_send(); } free(rtype); + return 0; } static void |