diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | channels.c | 460 | ||||
-rw-r--r-- | channels.h | 15 | ||||
-rw-r--r-- | compat.c | 33 | ||||
-rw-r--r-- | compat.h | 6 | ||||
-rw-r--r-- | dsa.c | 309 | ||||
-rw-r--r-- | dsa.h | 20 | ||||
-rw-r--r-- | hmac.c | 64 | ||||
-rw-r--r-- | hmac.h | 11 | ||||
-rw-r--r-- | kex.c | 407 | ||||
-rw-r--r-- | kex.h | 111 | ||||
-rw-r--r-- | nchan.c | 379 | ||||
-rw-r--r-- | nchan.h | 30 | ||||
-rw-r--r-- | nchan2.ms | 64 | ||||
-rw-r--r-- | packet.c | 514 | ||||
-rw-r--r-- | packet.h | 10 |
17 files changed, 2277 insertions, 166 deletions
@@ -1,5 +1,13 @@ 20000404 - Add tests for RAND_add function when searching for OpenSSL + - OpenBSD CVS update: + - [packet.h packet.c] + ssh2 packet format + - [packet.h packet.c nchan2.ms nchan.h compat.h compat.c] + [channels.h channels.c] + channel layer support for ssh2 + - [kex.h kex.c hmac.h hmac.c dsa.c dsa.h] + DSA, keyexchange, algorithm agreement for ssh2 20000403 - Wrote entropy collection routines for systems that lack /dev/random diff --git a/Makefile.in b/Makefile.in index 89b40848..bb08b53b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,7 +31,7 @@ LDFLAGS=-L. @LDFLAGS@ TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) -LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o key.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o +LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o @@ -13,10 +13,11 @@ * There is also code for initiating connection forwarding for X11 connections, * arbitrary tcp/ip connections, and the authentication agent connection. * + * SSH2 support added by Markus Friedl. */ #include "includes.h" -RCSID("$Id: channels.c,v 1.20 2000/04/01 01:09:23 damien Exp $"); +RCSID("$Id: channels.c,v 1.21 2000/04/04 04:39:00 damien Exp $"); #include "ssh.h" #include "packet.h" @@ -31,6 +32,8 @@ RCSID("$Id: channels.c,v 1.20 2000/04/01 01:09:23 damien Exp $"); #include "nchan.h" #include "compat.h" +#include "ssh2.h" + /* Maximum number of fake X11 displays to try. */ #define MAX_DISPLAYS 1000 @@ -165,6 +168,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, /* Do initial allocation if this is the first call. */ if (channels_alloc == 0) { + chan_init(); channels_alloc = 10; channels = xmalloc(channels_alloc * sizeof(Channel)); for (i = 0; i < channels_alloc; i++) @@ -237,9 +241,28 @@ channel_free(int id) if (c == NULL) packet_disconnect("channel free: bad local channel %d", id); debug("channel_free: channel %d: status: %s", id, channel_open_message()); + if (c->dettach_user != NULL) { + debug("channel_free: channel %d: dettaching channel user", id); + c->dettach_user(c->self, NULL); + } if (c->sock != -1) { shutdown(c->sock, SHUT_RDWR); close(c->sock); + c->sock = -1; + } + if (compat20) { + if (c->rfd != -1) { + close(c->rfd); + c->rfd = -1; + } + if (c->wfd != -1) { + close(c->wfd); + c->wfd = -1; + } + if (c->efd != -1) { + close(c->efd); + c->efd = -1; + } } buffer_free(&c->input); buffer_free(&c->output); @@ -296,6 +319,32 @@ channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset) } void +channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (c->istate == CHAN_INPUT_OPEN && + c->remote_window > 0 && + buffer_len(&c->input) < c->remote_window) + FD_SET(c->rfd, readset); + if (c->ostate == CHAN_OUTPUT_OPEN || + c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (buffer_len(&c->output) > 0) { + FD_SET(c->wfd, writeset); + } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + chan_obuf_empty(c); + } + } + /** XXX check close conditions, too */ + if (c->efd != -1) { + if (c->extended_usage == CHAN_EXTENDED_WRITE && + buffer_len(&c->extended) > 0) + FD_SET(c->efd, writeset); + else if (c->extended_usage == CHAN_EXTENDED_READ && + buffer_len(&c->extended) < c->remote_window) + FD_SET(c->efd, readset); + } +} + +void channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) { if (buffer_len(&c->input) == 0) { @@ -483,15 +532,27 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) SSH_CHANNEL_OPENING, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, 0, xstrdup(buf)); - - packet_start(SSH_MSG_PORT_OPEN); - packet_put_int(newch); - packet_put_string(c->path, strlen(c->path)); - packet_put_int(c->host_port); - if (have_hostname_in_open) { - packet_put_string(buf, strlen(buf)); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring("direct-tcpip"); + packet_put_int(newch); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + packet_put_string(c->path, strlen(c->path)); + packet_put_int(c->host_port); + packet_put_cstring(remote_hostname); + packet_put_int(remote_port); + packet_send(); + } else { + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(newch); + packet_put_string(c->path, strlen(c->path)); + packet_put_int(c->host_port); + if (have_hostname_in_open) { + packet_put_string(buf, strlen(buf)); + } + packet_send(); } - packet_send(); xfree(remote_hostname); } } @@ -569,6 +630,56 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) return -1; } buffer_consume(&c->output, len); + if (compat20 && len > 0) { + c->local_consumed += len; + } + } + return 1; +} +int +channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) +{ + char buf[16*1024]; + int len; + + if (c->efd != -1) { + if (c->extended_usage == CHAN_EXTENDED_WRITE && + FD_ISSET(c->efd, writeset) && + buffer_len(&c->extended) > 0) { + len = write(c->efd, buffer_ptr(&c->extended), + buffer_len(&c->extended)); + debug("channel %d: written %d to efd %d", + c->self, len, c->efd); + if (len > 0) { + buffer_consume(&c->extended, len); + c->local_consumed += len; + } + } else if (c->extended_usage == CHAN_EXTENDED_READ && + FD_ISSET(c->efd, readset)) { + len = read(c->efd, buf, sizeof(buf)); + debug("channel %d: read %d from efd %d", + c->self, len, c->efd); + if (len > 0) + buffer_append(&c->extended, buf, len); + } + } + return 1; +} +int +channel_check_window(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (!(c->flags & CHAN_CLOSE_SENT) && + c->local_window < c->local_window_max/2 && + c->local_consumed > 0) { + packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_put_int(c->remote_id); + packet_put_int(c->local_consumed); + packet_send(); + debug("channel %d: window %d sent adjust %d", + c->self, c->local_window, + c->local_consumed); + c->local_window += c->local_consumed; + c->local_consumed = 0; } return 1; } @@ -581,6 +692,15 @@ channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) } void +channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) +{ + channel_handle_rfd(c, readset, writeset); + channel_handle_wfd(c, readset, writeset); + channel_handle_efd(c, readset, writeset); + channel_check_window(c, readset, writeset); +} + +void channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) { int len; @@ -596,6 +716,16 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) } void +channel_handler_init_20(void) +{ + channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; + channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + + channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; + channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; +} + +void channel_handler_init_13(void) { channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; @@ -636,7 +766,9 @@ channel_handler_init(void) channel_pre[i] = NULL; channel_post[i] = NULL; } - if (compat13) + if (compat20) + channel_handler_init_20(); + else if (compat13) channel_handler_init_13(); else channel_handler_init_15(); @@ -660,8 +792,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) if (ftab[c->type] == NULL) continue; (*ftab[c->type])(c, readset, writeset); - if (!compat13) - chan_delete_if_full_closed(c); + chan_delete_if_full_closed(c); } } @@ -700,27 +831,39 @@ channel_output_poll() c->istate != CHAN_INPUT_WAIT_DRAIN) continue; } + if (compat20 && (c->flags & CHAN_CLOSE_SENT)) { + debug("channel: %d: no data after CLOSE", c->self); + continue; + } /* Get the amount of buffered data for this channel. */ len = buffer_len(&c->input); if (len > 0) { /* Send some data for the other side over the secure connection. */ - if (packet_is_interactive()) { - if (len > 1024) - len = 512; + if (compat20) { + if (len > c->remote_window) + len = c->remote_window; + if (len > c->remote_maxpacket) + len = c->remote_maxpacket; } else { - /* Keep the packets at reasonable size. */ - if (len > packet_get_maxsize()) - len = packet_get_maxsize()/2; + if (packet_is_interactive()) { + if (len > 1024) + len = 512; + } else { + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()/2) + len = packet_get_maxsize()/2; + } } if (len > 0) { - packet_start(SSH_MSG_CHANNEL_DATA); + packet_start(compat20 ? + SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(buffer_ptr(&c->input), len); packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; -debug("channel %d: send data len %d", c->self, len); + debug("channel %d: send data len %d", c->self, len); } } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { if (compat13) @@ -731,6 +874,23 @@ debug("channel %d: send data len %d", c->self, len); */ chan_ibuf_empty(c); } + /* Send extended data, i.e. stderr */ + if (compat20 && + c->remote_window > 0 && + (len = buffer_len(&c->extended)) > 0 && + c->extended_usage == CHAN_EXTENDED_READ) { + if (len > c->remote_window) + len = c->remote_window; + if (len > c->remote_maxpacket) + len = c->remote_maxpacket; + packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); + packet_put_int(c->remote_id); + packet_put_int(SSH2_EXTENDED_DATA_STDERR); + packet_put_string(buffer_ptr(&c->extended), len); + packet_send(); + buffer_consume(&c->extended, len); + c->remote_window -= len; + } } } @@ -766,10 +926,63 @@ channel_input_data(int type, int plen) /* Get the data. */ data = packet_get_string(&data_len); - packet_integrity_check(plen, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); + if (compat20){ + if (data_len > c->local_maxpacket) { + log("channel %d: rcvd big packet %d, maxpack %d", + c->self, data_len, c->local_maxpacket); + } + if (data_len > c->local_window) { + log("channel %d: rcvd too much data %d, win %d", + c->self, data_len, c->local_window); + xfree(data); + return; + } + c->local_window -= data_len; + }else{ + packet_integrity_check(plen, 4 + 4 + data_len, type); + } buffer_append(&c->output, data, data_len); xfree(data); } +void +channel_input_extended_data(int type, int plen) +{ + int id; + int tcode; + char *data; + unsigned int data_len; + Channel *c; + + /* Get the channel number and verify it. */ + id = packet_get_int(); + c = channel_lookup(id); + + if (c == NULL) + packet_disconnect("Received extended_data for bad channel %d.", id); + if (c->type != SSH_CHANNEL_OPEN) { + log("channel %d: ext data for non open", id); + return; + } + tcode = packet_get_int(); + if (c->efd == -1 || + c->extended_usage != CHAN_EXTENDED_WRITE || + tcode != SSH2_EXTENDED_DATA_STDERR) { + log("channel %d: bad ext data", c->self); + return; + } + data = packet_get_string(&data_len); + if (data_len > c->local_window) { + log("channel %d: rcvd too much extended_data %d, win %d", + c->self, data_len, c->local_window); + xfree(data); + return; + } + debug("channel %d: rcvd ext data %d", c->self, data_len); + c->local_window -= data_len; + buffer_append(&c->extended, data, data_len); + xfree(data); +} + /* * Returns true if no channel has too much buffered data, and false if one or @@ -785,7 +998,7 @@ channel_not_very_much_buffered_data() for (i = 0; i < channels_alloc; i++) { c = &channels[i]; if (c->type == SSH_CHANNEL_OPEN) { - if (buffer_len(&c->input) > packet_get_maxsize()) { + if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) { debug("channel %d: big input buffer %d", c->self, buffer_len(&c->input)); return 0; @@ -886,7 +1099,8 @@ channel_input_open_confirmation(int type, int plen) int id, remote_id; Channel *c; - packet_integrity_check(plen, 4 + 4, type); + if (!compat20) + packet_integrity_check(plen, 4 + 4, type); id = packet_get_int(); c = channel_lookup(id); @@ -898,6 +1112,18 @@ channel_input_open_confirmation(int type, int plen) /* Record the remote channel number and mark that the channel is now open. */ c->remote_id = remote_id; c->type = SSH_CHANNEL_OPEN; + + if (compat20) { + c->remote_window = packet_get_int(); + c->remote_maxpacket = packet_get_int(); + if (c->cb_fn != NULL && c->cb_event == type) { + debug("callback start"); + c->cb_fn(c->self, c->cb_arg); + debug("callback done"); + } + debug("channel %d: open confirm rwindow %d rmax %d", c->self, + c->remote_window, c->remote_maxpacket); + } } void @@ -906,7 +1132,8 @@ channel_input_open_failure(int type, int plen) int id; Channel *c; - packet_integrity_check(plen, 4, type); + if (!compat20) + packet_integrity_check(plen, 4, type); id = packet_get_int(); c = channel_lookup(id); @@ -914,11 +1141,64 @@ channel_input_open_failure(int type, int plen) if (c==NULL || c->type != SSH_CHANNEL_OPENING) packet_disconnect("Received open failure for " "non-opening channel %d.", id); - + if (compat20) { + int reason = packet_get_int(); + char *msg = packet_get_string(NULL); + log("channel_open_failure: %d: reason %d: %s", id, reason, msg); + xfree(msg); + } /* Free the channel. This will also close the socket. */ channel_free(id); } +void +channel_input_channel_request(int type, int plen) +{ + int id; + Channel *c; + + id = packet_get_int(); + c = channel_lookup(id); + + if (c == NULL || + (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL)) + packet_disconnect("Received request for " + "non-open channel %d.", id); + if (c->cb_fn != NULL && c->cb_event == type) { + debug("callback start"); + c->cb_fn(c->self, c->cb_arg); + debug("callback done"); + } else { + char *service = packet_get_string(NULL); + debug("channel: %d rcvd request for %s", c->self, service); +debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event); + xfree(service); + } +} + +void +channel_input_window_adjust(int type, int plen) +{ + Channel *c; + int id, adjust; + + if (!compat20) + return; + + /* Get the channel number and verify it. */ + id = packet_get_int(); + c = channel_lookup(id); + + if (c == NULL || c->type != SSH_CHANNEL_OPEN) { + log("Received window adjust for " + "non-open channel %d.", id); + return; + } + adjust = packet_get_int(); + debug("channel %d: rcvd adjust %d", id, adjust); + c->remote_window += adjust; +} + /* * Stops listening for channels, and removes any unix domain sockets that we * might have. @@ -983,6 +1263,10 @@ channel_still_open() case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: continue; + case SSH_CHANNEL_LARVAL: + if (!compat20) + fatal("cannot happen: SSH_CHANNEL_LARVAL"); + continue; case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: @@ -1024,6 +1308,7 @@ channel_open_message() case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: continue; + case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: @@ -1156,17 +1441,26 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne num_permitted_opens++; /* Send the forward request to the remote side. */ - packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); - packet_put_int(port_to_connect); - packet_put_string(host_to_connect, strlen(host_to_connect)); - packet_put_int(listen_port); - packet_send(); - packet_write_wait(); - /* - * Wait for response from the remote side. It will send a disconnect - * message on failure, and we will never see it here. - */ - packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); + if (compat20) { + const char *address_to_bind = "0.0.0.0"; + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("tcpip-forward"); + packet_put_char(0); /* boolean: want reply */ + packet_put_cstring(address_to_bind); + packet_put_int(listen_port); + } else { + packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); + packet_put_int(port_to_connect); + packet_put_cstring(host_to_connect); + packet_put_int(listen_port); + packet_send(); + packet_write_wait(); + /* + * Wait for response from the remote side. It will send a disconnect + * message on failure, and we will never see it here. + */ + packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); + } } /* @@ -1839,3 +2133,97 @@ auth_input_open_request(int type, int plen) packet_put_int(newch); packet_send(); } + +void +channel_open(int id) +{ + Channel *c = channel_lookup(id); + if (c == NULL) { + log("channel_open: %d: bad id", id); + return; + } + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring(c->ctype); + packet_put_int(c->self); + packet_put_int(c->local_window); + packet_put_int(c->local_maxpacket); + packet_send(); + debug("channel open %d", id); +} +void +channel_request(int id, char *service, int wantconfirm) +{ + channel_request_start(id, service, wantconfirm); + packet_send(); + debug("channel request %d: %s", id, service) ; +} +void +channel_request_start(int id, char *service, int wantconfirm) +{ + Channel *c = channel_lookup(id); + if (c == NULL) { + log("channel_request: %d: bad id", id); + return; + } + packet_start(SSH2_MSG_CHANNEL_REQUEST); + packet_put_int(c->remote_id); + packet_put_cstring(service); + packet_put_char(wantconfirm); +} +void +channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg) +{ + Channel *c = channel_lookup(id); + if (c == NULL) { + log("channel_register_callback: %d: bad id", id); + return; + } + c->cb_event = mtype; + c->cb_fn = fn; + c->cb_arg = arg; +} +void +channel_register_cleanup(int id, channel_callback_fn *fn) +{ + Channel *c = channel_lookup(id); + if (c == NULL) { + log("channel_register_cleanup: %d: bad id", id); + return; + } + c->dettach_user = fn; +} +void +channel_cancel_cleanup(int id) +{ + Channel *c = channel_lookup(id); + if (c == NULL) { + log("channel_cancel_cleanup: %d: bad id", id); + return; + } + c->dettach_user = NULL; +} + +void +channel_set_fds(int id, int rfd, int wfd, int efd, int extusage) +{ + Channel *c = channel_lookup(id); + if (c == NULL || c->type != SSH_CHANNEL_LARVAL) + fatal("channel_activate for non-larval channel %d.", id); + if (rfd > channel_max_fd_value) + channel_max_fd_value = rfd; + if (wfd > channel_max_fd_value) + channel_max_fd_value = wfd; + if (efd > channel_max_fd_value) + channel_max_fd_value = efd; + c->type = SSH_CHANNEL_OPEN; + c->rfd = rfd; + c->wfd = wfd; + c->efd = efd; + c->extended_usage = extusage; + /* XXX window size? */ + c->local_window = c->local_window_max = c->local_maxpacket/2; + packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_put_int(c->remote_id); + packet_put_int(c->local_window); + packet_send(); +} @@ -1,4 +1,4 @@ -/* RCSID("$Id: channels.h,v 1.5 2000/04/01 01:09:23 damien Exp $"); */ +/* RCSID("$Id: channels.h,v 1.6 2000/04/04 04:39:01 damien Exp $"); */ #ifndef CHANNELS_H #define CHANNELS_H @@ -30,6 +30,7 @@ typedef struct Channel { /* peer can be reached over encrypted connection, via packet-sent */ int istate; /* input from channel (state of receive half) */ int ostate; /* output to channel (state of transmit half) */ + int flags; /* close sent/rcvd */ int rfd; /* read fd */ int wfd; /* write fd */ int efd; /* extended fd */ @@ -66,21 +67,30 @@ typedef struct Channel { #define CHAN_EXTENDED_READ 1 #define CHAN_EXTENDED_WRITE 2 +void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage); void channel_open(int id); +void channel_request(int id, char *service, int wantconfirm); +void channel_request_start(int id, char *service, int wantconfirm); +void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg); +void channel_register_cleanup(int id, channel_callback_fn *fn); +void channel_cancel_cleanup(int id); Channel *channel_lookup(int id); int channel_new(char *ctype, int type, int rfd, int wfd, int efd, int window, int maxpack, int extended_usage, char *remote_name); +void channel_input_channel_request(int type, int plen); void channel_input_close(int type, int plen); void channel_input_close_confirmation(int type, int plen); void channel_input_data(int type, int plen); +void channel_input_extended_data(int type, int plen); void channel_input_ieof(int type, int plen); void channel_input_oclose(int type, int plen); void channel_input_open_confirmation(int type, int plen); void channel_input_open_failure(int type, int plen); void channel_input_port_open(int type, int plen); +void channel_input_window_adjust(int type, int plen); void channel_input_open(int type, int plen); /* Sets specific protocol options. */ @@ -218,4 +228,7 @@ void auth_input_request_forwarding(struct passwd * pw); /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ void auth_input_open_request(int type, int plen); +/* XXX */ +int channel_connect_to(const char *host, u_short host_port); + #endif @@ -28,15 +28,46 @@ */ #include "includes.h" -RCSID("$Id: compat.c,v 1.3 1999/11/25 00:54:59 damien Exp $"); +RCSID("$Id: compat.c,v 1.4 2000/04/04 04:39:01 damien Exp $"); #include "ssh.h" +#include "packet.h" int compat13 = 0; +int compat20 = 0; +int datafellows = 0; void +enable_compat20(void) +{ + fatal("protocol 2.0 not implemented"); +} +void enable_compat13(void) { verbose("Enabling compatibility mode for protocol 1.3"); compat13 = 1; } +/* datafellows bug compatibility */ +void +compat_datafellows(const char *version) +{ + int i; + size_t len; + static const char *check[] = { + "2.0.1", + "2.1.0.beta.9", + "2.1.0.pre.3", + "2.1.0.public.beta.1", + NULL + }; + for (i = 0; check[i]; i++) { + len = strlen(check[i]); + if (strlen(version) >= len && + (strncmp(version, check[i], len) == 0)) { + log("datafellows: %.200s", version); + datafellows = 1; + return; + } + } +} @@ -26,10 +26,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$Id: compat.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */ +/* RCSID("$Id: compat.h,v 1.4 2000/04/04 04:39:01 damien Exp $"); */ #ifndef COMPAT_H #define COMPAT_H void enable_compat13(void); +void enable_compat20(void); +void compat_datafellows(const char *s); extern int compat13; +extern int compat20; +extern int datafellows; #endif @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Markus Friedl. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$Id: dsa.c,v 1.1 2000/04/03 20:06:14 markus Exp $"); + +#include "ssh.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" + +#if HAVE_OPENSSL +# include <openssl/bn.h> +# include <openssl/dh.h> +# include <openssl/rsa.h> +# include <openssl/dsa.h> +# include <openssl/evp.h> +# include <openssl/bio.h> +# include <openssl/pem.h> +#endif /* HAVE_OPENSSL */ +#if HAVE_SSL +# include <ssl/bn.h> +# include <ssl/dh.h> +# include <ssl/rsa.h> +# include <ssl/dsa.h> +# include <ssl/evp.h> +# include <ssl/bio.h> +# include <ssl/pem.h> +#endif /* HAVE_SSL */ + +#include <ssl/hmac.h> +#include "kex.h" +#include "key.h" + +#define INTBLOB_LEN 20 +#define SIGBLOB_LEN (2*INTBLOB_LEN) + +Key * +dsa_serverkey_from_blob( + char *serverhostkey, int serverhostkeylen) +{ + Buffer b; + char *ktype; + int rlen; + DSA *dsa; + Key *key; + + /* fetch & parse DSA/DSS pubkey */ + key = key_new(KEY_DSA); + dsa = key->dsa; + buffer_init(&b); + buffer_append(&b, serverhostkey, serverhostkeylen); + ktype = buffer_get_string(&b, NULL); + if (strcmp(KEX_DSS, ktype) != 0) { + log("dsa_serverkey_from_blob: cannot handle type %s", ktype); + key_free(key); + return NULL; + } + buffer_get_bignum2(&b, dsa->p); + buffer_get_bignum2(&b, dsa->q); + buffer_get_bignum2(&b, dsa->g); + buffer_get_bignum2(&b, dsa->pub_key); + rlen = buffer_len(&b); + if(rlen != 0) + log("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen); + buffer_free(&b); + + log("keytype %s", ktype); +#ifdef DEBUG_DSS + DSA_print_fp(stderr, dsa, 8); +#endif + return key; +} +DSA * +dsa_load_private(char *filename) +{ + DSA *dsa; + BIO *in; + + in = BIO_new(BIO_s_file()); + if (in == NULL) + fatal("BIO_new failed"); + if (BIO_read_filename(in, filename) <= 0) + fatal("BIO_read failed %s: %s", filename, strerror(errno)); + fprintf(stderr, "read DSA private key\n"); + dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL); + if (dsa == NULL) + fatal("PEM_read_bio_DSAPrivateKey failed %s", filename); + BIO_free(in); + return dsa; +} +Key * +dsa_get_serverkey(char *filename) +{ + Key *k = key_new(KEY_EMPTY); + k->type = KEY_DSA; + k->dsa = dsa_load_private(filename); +#ifdef DEBUG_DSS + DSA_print_fp(stderr, dsa, 8); +#endif + return k; +} +int +dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp) +{ + Buffer b; + int len; + unsigned char *buf; + + if (key == NULL || key->type != KEY_DSA) + return 0; + buffer_init(&b); + buffer_put_cstring(&b, KEX_DSS); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_p |