diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2000-04-03 07:07:16 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2000-04-03 07:07:16 +0000 |
commit | 31a956aea7b3c5c953c73c65adcc68f36b228061 (patch) | |
tree | 8e341ae42e3cf23e46ddac2589c29ab5cb000ce2 | |
parent | dc4f9fc832068043e95bb414dd660fa24166f8bf (diff) |
channel layer support for ssh2
-rw-r--r-- | usr.bin/ssh/channels.c | 460 | ||||
-rw-r--r-- | usr.bin/ssh/channels.h | 15 | ||||
-rw-r--r-- | usr.bin/ssh/compat.c | 33 | ||||
-rw-r--r-- | usr.bin/ssh/compat.h | 6 | ||||
-rw-r--r-- | usr.bin/ssh/nchan.c | 379 | ||||
-rw-r--r-- | usr.bin/ssh/nchan.h | 30 | ||||
-rw-r--r-- | usr.bin/ssh/nchan2.ms | 64 | ||||
-rw-r--r-- | usr.bin/ssh/packet.c | 34 | ||||
-rw-r--r-- | usr.bin/ssh/packet.h | 7 |
9 files changed, 906 insertions, 122 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c index a02231992c0..5e0bd650221 100644 --- a/usr.bin/ssh/channels.c +++ b/usr.bin/ssh/channels.c @@ -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.43 2000/03/28 20:39:05 markus Exp $"); +RCSID("$Id: channels.c,v 1.44 2000/04/03 07:07:15 markus Exp $"); #include "ssh.h" #include "packet.h" @@ -31,6 +32,8 @@ RCSID("$Id: channels.c,v 1.43 2000/03/28 20:39:05 markus 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: @@ -1152,17 +1437,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); + } } /* @@ -1783,3 +2077,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(); +} diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h index 7d639035820..840f885a3c4 100644 --- a/usr.bin/ssh/channels.h +++ b/usr.bin/ssh/channels.h @@ -1,4 +1,4 @@ -/* RCSID("$Id: channels.h,v 1.7 2000/03/28 20:31:26 markus Exp $"); */ +/* RCSID("$Id: channels.h,v 1.8 2000/04/03 07:07:15 markus 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 diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c index 7e21fd080a8..a4579b46013 100644 --- a/usr.bin/ssh/compat.c +++ b/usr.bin/ssh/compat.c @@ -28,15 +28,46 @@ */ #include "includes.h" -RCSID("$Id: compat.c,v 1.5 1999/11/24 16:15:24 markus Exp $"); +RCSID("$Id: compat.c,v 1.6 2000/04/03 07:07:15 markus 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; + } + } +} diff --git a/usr.bin/ssh/compat.h b/usr.bin/ssh/compat.h index 68d5e2bd792..2e0928c7629 100644 --- a/usr.bin/ssh/compat.h +++ b/usr.bin/ssh/compat.h @@ -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.4 1999/11/24 16:15:24 markus Exp $"); */ +/* RCSID("$Id: compat.h,v 1.5 2000/04/03 07:07:15 markus 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 diff --git a/usr.bin/ssh/nchan.c b/usr.bin/ssh/nchan.c index 58c68d6b332..3e30548c295 100644 --- a/usr.bin/ssh/nchan.c +++ b/usr.bin/ssh/nchan.c @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$Id: nchan.c,v 1.12 2000/03/28 20:34:14 markus Exp $"); +RCSID("$Id: nchan.c,v 1.13 2000/04/03 07:07:15 markus Exp $"); #include "ssh.h" @@ -37,138 +37,169 @@ RCSID("$Id: nchan.c,v 1.12 2000/03/28 20:34:14 markus Exp $"); #include "channels.h" #include "nchan.h" -static void chan_send_ieof(Channel *c); -static void chan_send_oclose(Channel *c); -static void chan_shutdown_write(Channel *c); -static void chan_shutdown_read(Channel *c); +#include "ssh2.h" +#include "compat.h" +/* functions manipulating channel states */ /* * EVENTS update channel input/output states execute ACTIONS */ - /* events concerning the INPUT from socket for channel (istate) */ -void -chan_rcvd_oclose(Channel *c) +chan_event_fn *chan_rcvd_oclose = NULL; +chan_event_fn *chan_read_failed = NULL; +chan_event_fn *chan_ibuf_empty = NULL; +/* events concerning the OUTPUT from channel for socket (ostate) */ +chan_event_fn *chan_rcvd_ieof = NULL; +chan_event_fn *chan_write_failed = NULL; +chan_event_fn *chan_obuf_empty = NULL; +/* + * ACTIONS: should never update the channel states + */ +static void chan_send_ieof1(Channel *c); +static void chan_send_oclose1(Channel *c); +static void chan_send_close2(Channel *c); +static void chan_send_eof2(Channel *c); + +/* channel cleanup */ +chan_event_fn *chan_delete_if_full_closed = NULL; + +/* helper */ +static void chan_shutdown_write(Channel *c); +static void chan_shutdown_read(Channel *c); + +/* + * SSH1 specific implementation of event functions + */ + +static void +chan_rcvd_oclose1(Channel *c) { + debug("channel %d: rcvd oclose", c->self); switch (c->istate) { case CHAN_INPUT_WAIT_OCLOSE: - debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self); + debug("channel %d: input wait_oclose -> closed", c->self); c->istate = CHAN_INPUT_CLOSED; break; case CHAN_INPUT_OPEN: - debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); + debug("channel %d: input open -> closed", c->self); chan_shutdown_read(c); - chan_send_ieof(c); + chan_send_ieof1(c); c->istate = CHAN_INPUT_CLOSED; break; case CHAN_INPUT_WAIT_DRAIN: /* both local read_failed and remote write_failed */ - log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); - debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); - chan_send_ieof(c); + log("channel %d: input drain -> closed", c->self); + chan_send_ieof1(c); c->istate = CHAN_INPUT_CLOSED; break; default: - error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate); + error("channel %d: protocol error: chan_rcvd_oclose for istate %d", + c->self, c->istate); return; } } -void -chan_read_failed(Channel *c) +static void +chan_read_failed_12(Channel *c) { + debug("channel %d: read failed", c->self); switch (c->istate) { case CHAN_INPUT_OPEN: - debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self); + debug("channel %d: input open -> drain", c->self); chan_shutdown_read(c); c->istate = CHAN_INPUT_WAIT_DRAIN; break; default: - error("internal error: we do not read, but chan_read_failed %d for istate %d", - c->self, c->istate); + error("channel %d: internal error: we do not read, but chan_read_failed for istate %d", + c->self, c->istate); break; } } -void -chan_ibuf_empty(Channel *c) +static void +chan_ibuf_empty1(Channel *c) { + debug("channel %d: ibuf empty", c->self); if (buffer_len(&c->input)) { - error("internal error: chan_ibuf_empty %d for non empty buffer", c->self); + error("channel %d: internal error: chan_ibuf_empty for non empty buffer", + c->self); return; } switch (c->istate) { case CHAN_INPUT_WAIT_DRAIN: - debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self); - chan_send_ieof(c); + debug("channel %d: input drain -> wait_oclose", c->self); + chan_send_ieof1(c); c->istate = CHAN_INPUT_WAIT_OCLOSE; break; default: - error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate); + error("channel %d: internal error: chan_ibuf_empty for istate %d", + c->self, c->istate); break; } } - -/* events concerning the OUTPUT from channel for socket (ostate) */ -void -chan_rcvd_ieof(Channel *c) +static void +chan_rcvd_ieof1(Channel *c) { + debug("channel %d: rcvd ieof", c->self); switch (c->ostate) { case CHAN_OUTPUT_OPEN: - debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self); + debug("channel %d: output open -> drain", c->self); c->ostate = CHAN_OUTPUT_WAIT_DRAIN; break; case CHAN_OUTPUT_WAIT_IEOF: - debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); + debug("channel %d: output wait_ieof -> closed", c->self); c->ostate = CHAN_OUTPUT_CLOSED; break; default: - error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate); + error("channel %d: protocol error: chan_rcvd_ieof for ostate %d", + c->self, c->ostate); break; } } -void -chan_write_failed(Channel *c) +static void +chan_write_failed1(Channel *c) { + debug("channel %d: write failed", c->self); switch (c->ostate) { case CHAN_OUTPUT_OPEN: - debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self); - chan_send_oclose(c); + debug("channel %d: output open -> wait_ieof", c->self); + chan_send_oclose1(c); c->ostate = CHAN_OUTPUT_WAIT_IEOF; break; case CHAN_OUTPUT_WAIT_DRAIN: - debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); - chan_send_oclose(c); + debug("channel %d: output wait_drain -> closed", c->self); + chan_send_oclose1(c); c->ostate = CHAN_OUTPUT_CLOSED; break; default: - error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate); + error("channel %d: internal error: chan_write_failed for ostate %d", + c->self, c->ostate); break; } } -void -chan_obuf_empty(Channel *c) +static void +chan_obuf_empty1(Channel *c) { + debug("channel %d: obuf empty", c->self); if (buffer_len(&c->output)) { - debug("internal error: chan_obuf_empty %d for non empty buffer", c->self); + error("channel %d: internal error: chan_obuf_empty for non empty buffer", + c->self); return; } switch (c->ostate) { case CHAN_OUTPUT_WAIT_DRAIN: - debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); - chan_send_oclose(c); + debug("channel %d: output drain -> closed", c->self); + chan_send_oclose1(c); c->ostate = CHAN_OUTPUT_CLOSED; break; default: - error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate); + error("channel %d: internal error: chan_obuf_empty for ostate %d", + c->self, c->ostate); break; } } - -/* - * ACTIONS: should never update the channel states: c->istate or c->ostate - */ static void -chan_send_ieof(Channel *c) +chan_send_ieof1(Channel *c) { + debug("channel %d: send ieof", c->self); switch (c->istate) { case CHAN_INPUT_OPEN: case CHAN_INPUT_WAIT_DRAIN: @@ -177,13 +208,15 @@ chan_send_ieof(Channel *c) packet_send(); break; default: - error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate); + error("channel %d: internal error: cannot send ieof for istate %d", + c->self, c->istate); break; } } static void -chan_send_oclose(Channel *c) +chan_send_oclose1(Channel *c) { + debug("channel %d: send oclose", c->self); switch (c->ostate) { case CHAN_OUTPUT_OPEN: case CHAN_OUTPUT_WAIT_DRAIN: @@ -194,40 +227,246 @@ chan_send_oclose(Channel *c) packet_send(); break; default: - error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate); + error("channel %d: internal error: cannot send oclose for ostate %d", + c->self, c->ostate); break; } } +static void +chan_delete_if_full_closed1(Channel *c) +{ + if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { + debug("channel %d: full closed", c->self); + channel_free(c->self); + } +} -/* helper */ +/* + * the same for SSH2 + */ static void -chan_shutdown_write(Channel *c) +chan_rcvd_oclose2(Channel *c) { - /* shutdown failure is allowed if write failed already */ - debug("channel %d: shutdown_write", c->self); - if (shutdown(c->sock, SHUT_WR) < 0) - debug("chan_shutdown_write failed for #%d/fd%d: %.100s", - c->self, c->sock, strerror(errno)); + debug("channel %d: rcvd close", c->self); + if (c->flags & CHAN_CLOSE_RCVD) + error("channel %d: protocol error: close rcvd twice", c->self); + c->flags |= CHAN_CLOSE_RCVD; + if (c->type == SSH_CHANNEL_LARVAL) { + /* tear down larval channels immediately */ + c->ostate = CHAN_OUTPUT_CLOSED; + c->istate = CHAN_INPUT_CLOSED; + return; + } + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + /* wait until a data from the channel is consumed if a CLOSE is received */ + debug("channel %d: output open -> drain", c->self); + c->ostate = CHAN_OUTPUT_WAIT_DRAIN; + break; + } + switch (c->istate) { + case CHAN_INPUT_OPEN: + debug("channel %d: input open -> closed", c->self); + chan_shutdown_read(c); + break; + case CHAN_INPUT_WAIT_DRAIN: + debug("channel %d: input drain -> closed", c->self); + chan_send_eof2(c); + break; + } + c->istate = CHAN_INPUT_CLOSED; } static void -chan_shutdown_read(Channel *c) +chan_ibuf_empty2(Channel *c) +{ + debug("channel %d: ibuf empty", c->self); + if (buffer_len(&c->input)) { + error("channel %d: internal error: chan_ibuf_empty for non empty buffer", + c->self); + return; + } + switch (c->istate) { + case CHAN_INPUT_WAIT_DRAIN: + debug("channel %d: input drain -> closed", c->self); + if (!(c->flags & CHAN_CLOSE_SENT)) + chan_send_eof2(c); + c->istate = CHAN_INPUT_CLOSED; + break; + default: + error("channel %d: internal error: chan_ibuf_empty for istate %d", + c->self, c->istate); + break; + } +} +static void +chan_rcvd_ieof2(Channel *c) { - debug("channel %d: shutdown_read", c->self); - if (shutdown(c->sock, SHUT_RD) < 0) - error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s", - c->self, c->sock, c->istate, c->ostate, strerror(errno)); + debug("channel %d: rcvd eof", c->self); + if (c->ostate == CHAN_OUTPUT_OPEN) { + debug("channel %d: output open -> drain", c->self); + c->ostate = CHAN_OUTPUT_WAIT_DRAIN; + } } -void -chan_delete_if_full_closed(Channel *c) +static void +chan_write_failed2(Channel *c) +{ + debug("channel %d: write failed", c->self); + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + debug("channel %d: output open -> closed", c->self); + chan_shutdown_write(c); // ?? + c->ostate = CHAN_OUTPUT_CLOSED; + break; + case CHAN_OUTPUT_WAIT_DRAIN: + debug("channel %d: output drain -> closed", c->self); + chan_shutdown_write(c); + c->ostate = CHAN_OUTPUT_CLOSED; + break; + default: + error("channel %d: internal error: chan_write_failed for ostate %d", + c->self, c->ostate); + break; + } +} +static void +chan_obuf_empty2(Channel *c) +{ + debug("channel %d: obuf empty", c->self); + if (buffer_len(&c->output)) { + error("internal error: chan_obuf_empty %d for non empty buffer", + c->self); + return; + } + switch (c->ostate) { + case CHAN_OUTPUT_WAIT_DRAIN: + debug("channel %d: output drain -> closed", c->self); + chan_shutdown_write(c); + c->ostate = CHAN_OUTPUT_CLOSED; + break; + default: + error("channel %d: internal error: chan_obuf_empty for ostate %d", + c->self, c->ostate); + break; + } +} +static void +chan_send_eof2(Channel *c) +{ + debug("channel %d: send eof", c->self); + switch (c->istate) { + case CHAN_INPUT_WAIT_DRAIN: + packet_start(SSH2_MSG_CHANNEL_EOF); + packet_put_int(c->remote_id); + packet_send(); + break; + default: + error("channel %d: internal error: cannot send eof for istate %d", + c->self, c->istate); + break; + } +} +static void +chan_send_close2(Channel *c) +{ + debug("channel %d: send close", c->self); + if (c->ostate != CHAN_OUTPUT_CLOSED || + c->istate != CHAN_INPUT_CLOSED) { + error("channel %d: internal error: cannot send close for istate/ostate %d/%d", + c->self, c->istate, c->ostate); + } else if (c->flags & CHAN_CLOSE_SENT) { + error("channel %d: internal error: already sent close", c->self); + } else { + packet_start(SSH2_MSG_CHANNEL_CLOSE); + packet_put_int(c->remote_id); + packet_send(); + c->flags |= CHAN_CLOSE_SENT; + } +} +static void +chan_delete_if_full_closed2(Channel *c) { if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { - debug("channel %d: full closed", c->self); - channel_free(c->self); + if (!(c->flags & CHAN_CLOSE_SENT)) { + chan_send_close2(c); + } + if ((c->flags & CHAN_CLOSE_SENT) && + (c->flags & CHAN_CLOSE_RCVD)) { + debug("channel %d: full closed2", c->self); + channel_free(c->self); + } } } + +/* shared */ void chan_init_iostates(Channel *c) { c->ostate = CHAN_OUTPUT_OPEN; c->istate = CHAN_INPUT_OPEN; + c->flags = 0; +} + +/* init */ +void +chan_init(void) +{ + if (compat20) { + chan_rcvd_oclose = chan_rcvd_oclose2; + chan_read_failed = chan_read_failed_12; + chan_ibuf_empty = chan_ibuf_empty2; + + chan_rcvd_ieof = chan_rcvd_ieof2; + chan_write_failed = chan_write_failed2; + chan_obuf_empty = chan_obuf_empty2; + + chan_delete_if_full_closed = chan_delete_if_full_closed2; + } else { + chan_rcvd_oclose = chan_rcvd_oclose1; + chan_read_failed = chan_read_failed_12; + chan_ibuf_empty = chan_ibuf_empty1; + + chan_rcvd_ieof = chan_rcvd_ieof1; + chan_write_failed = chan_write_failed1; + chan_obuf_empty = chan_obuf_empty1; + + chan_delete_if_full_closed = chan_delete_if_full_closed1; + } +} + +/* helper */ +static void +chan_shutdown_write(Channel *c) +{ + buffer_consume(&c->output, buffer_len(&c->output)); + if (compat20 && c->type == SSH_CHANNEL_LARVAL) + return; + /* shutdown failure is allowed if write failed already */ + debug("channel %d: close_write", c->self); + if (c->sock != -1) { + if (shutdown(c->sock, SHUT_WR) < 0) + debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s", + c->self, c->sock, strerror(errno)); + } else { + if (close(c->wfd) < 0) + log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s", + c->self, c->wfd, strerror(errno)); + c->wfd = -1; + } +} +static void +chan_shutdown_read(Channel *c) +{ + if (compat20 && c->type == SSH_CHANNEL_LARVAL) + return; + debug("channel %d: close_read", c->self); + if (c->sock != -1) { + if (shutdown(c->sock, SHUT_RD) < 0) + error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s", + c->self, c->sock, c->istate, c->ostate, strerror(errno)); + } else { + if (close(c->rfd) < 0) + log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s", + c->self, c->rfd, strerror(errno)); + c->rfd = -1; + } } diff --git a/usr.bin/ssh/nchan.h b/usr.bin/ssh/nchan.h index 85528c850a5..0a2cf35f781 100644 --- a/usr.bin/ssh/nchan.h +++ b/usr.bin/ssh/nchan.h @@ -27,7 +27,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* RCSID("$Id: nchan.h,v 1.6 2000/03/28 20:31:27 markus Exp $"); */ +/* RCSID("$Id: nchan.h,v 1.7 2000/04/03 07:07:15 markus Exp $"); */ #ifndef NCHAN_H #define NCHAN_H @@ -72,17 +72,25 @@ #define CHAN_OUTPUT_WAIT_IEOF 0x40 #define CHAN_OUTPUT_CLOSED 0x80 -/* EVENTS for the input state */ -void chan_rcvd_oclose(Channel * c); -void chan_read_failed(Channel * c); -void chan_ibuf_empty(Channel * c); +#define CHAN_CLOSE_SENT 0x01 +#define CHAN_CLOSE_RCVD 0x02 -/* EVENTS for the output state */ -void chan_rcvd_ieof(Channel * c); -void chan_write_failed(Channel * c); -void chan_obuf_empty(Channel * c); -void chan_init_iostates(Channel * c); +/* Channel EVENTS */ +typedef void chan_event_fn(Channel * c); + +/* for the input state */ +extern chan_event_fn *chan_rcvd_oclose; +extern chan_event_fn *chan_read_failed; +extern chan_event_fn *chan_ibuf_empty; + +/* for the output state */ +extern chan_event_fn *chan_rcvd_ieof; +extern chan_event_fn *chan_write_failed; +extern chan_event_fn *chan_obuf_empty; -void chan_delete_if_full_closed(Channel *c); +extern chan_event_fn *chan_delete_if_full_closed; + +void chan_init_iostates(Channel * c); +void chan_init(void); #endif diff --git a/usr.bin/ssh/nchan2.ms b/usr.bin/ssh/nchan2.ms new file mode 100644 index 00000000000..1b119d1353b --- /dev/null +++ b/usr.bin/ssh/nchan2.ms @@ -0,0 +1,64 @@ +.TL +OpenSSH Channel Close Protocol 2.0 Implementation +.SH +Channel Input State Diagram +.PS +reset +l=1 +s=1.2 +ellipsewid=s*ellipsewid +boxwid=s*boxwid +ellipseht=s*ellipseht +S1: ellipse "INPUT" "OPEN" +move right 2*l from last ellipse.e +S3: ellipse invis +move down l from last ellipse.s +S4: ellipse "INPUT" "CLOSED" +move down l from 1st ellipse.s +S2: ellipse "INPUT" "WAIT" "DRAIN" +arrow from S1.e to S4.n +box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c +arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w +arrow from S1.s to S2.n +box invis "read_failed/" "shutdown_read" with .e at last arrow.c +ellipse wid .9*ellipsewid ht .9*ellipseht at S4 +arrow "start" "" from S1.w+(-0.5,0) to S1.w +.PE +.SH +Channel Output State Diagram +.PS +S1: ellipse "OUTPUT" "OPEN" +move right 2*l from last ellipse.e +S3: ellipse invis +move down l from last ellipse.s +S4: ellipse "OUTPUT" "CLOSED" +move down l from 1st ellipse.s +S2: ellipse "OUTPUT" "WAIT" "DRAIN" +arrow from S1.e to S4.n +box invis "write_failed/" "shutdown_write" with .sw at last arrow.c +arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w +arrow from S1.s to S2.n +box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c +ellipse wid .9*ellipsewid ht .9*ellipseht at S4 +arrow "start" "" from S1.w+(-0.5,0) to S1.w +.PE +.SH +Notes +.PP +The input buffer is filled with data from the socket +(the socket represents the local consumer/producer of the +forwarded channel). +The data is then sent over the INPUT-end (transmit-end) of the channel to the +remote peer. +Data sent by the peer is received on the OUTPUT-end (receive-end), +saved in the output buffer and written to the socket. +.PP +If the local protocol instance has forwarded all data on the +INPUT-end of the channel, it sends an EOF message to the peer. +.PP +A CLOSE message is sent to the peer if +both the INPUT- and the OUTOUT-half of the local +end of the channel are closed. +.PP +The channel can be deallocated by a protocol instance +if a CLOSE message he been both sent and received. diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c index 23aee637a6c..901b2ed606e 100644 --- a/usr.bin/ssh/packet.c +++ b/usr.bin/ssh/packet.c @@ -15,7 +15,7 @@ */ #include "includes.h" -RCSID("$Id: packet.c,v 1.23 2000/03/28 20:31:27 markus Exp $"); +RCSID("$Id: packet.c,v 1.24 2000/04/03 07:07:15 markus Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -333,6 +333,18 @@ packet_put_string(const char *buf, unsigned int len) { buffer_put_string(&outgoing_packet, buf, len); } +void +packet_put_cstring(const char *str) +{ + buffer_put_string(&outgoing_packet, str, strlen(str)); +} + +void +packet_put_raw(const char *buf, unsigned int len) +{ + buffer_append(&outgoing_packet, buf, len); +} + /* Appends an arbitrary precision integer to packet data. */ @@ -341,6 +353,11 @@ packet_put_bignum(BIGNUM * value) { buffer_put_bignum(&outgoing_packet, value); } +void +packet_put_bignum2(BIGNUM * value) +{ + buffer_put_bignum2(&outgoing_packet, value); +} /* * Finalizes and sends the packet. If the encryption key has been set, @@ -637,6 +654,21 @@ packet_get_bignum(BIGNUM * value, int *length_ptr) *length_ptr = buffer_get_bignum(&incoming_packet, value); } +void +packet_get_bignum2(BIGNUM * value, int *length_ptr) +{ + *length_ptr = buffer_get_bignum2(&incoming_packet, value); +} + +char * +packet_get_raw(int *length_ptr) +{ + int bytes = buffer_len(&incoming_packet); + if (length_ptr != NULL) + *length_ptr = bytes; + return buffer_ptr(&incoming_packet); +} + /* * Returns a string from the packet data. The string is allocated using * xmalloc; it is the responsibility of the calling program to free it when diff --git a/usr.bin/ssh/packet.h b/usr.bin/ssh/packet.h index 66a35286d6a..45390916f8f 100644 --- a/usr.bin/ssh/packet.h +++ b/usr.bin/ssh/packet.h @@ -13,7 +13,7 @@ * */ -/* RCSID("$Id: packet.h,v 1.10 2000/03/16 20:56:14 markus Exp $"); */ +/* RCSID("$Id: packet.h,v 1.11 2000/04/03 07:07:15 markus Exp $"); */ #ifndef PACKET_H #define PACKET_H @@ -83,9 +83,12 @@ void packet_put_int(unsigned int value); /* Appends an arbitrary precision integer to packet data. */ void packet_put_bignum(BIGNUM * value); +void packet_put_bignum2(BIGNUM * value); /* Appends a string to packet data. */ void packet_put_string(const char *buf, unsigned int len); +void packet_put_cstring(const char *str); +void packet_put_raw(const char *buf, unsigned int len); /* * Finalizes and sends the packet. If the encryption key has been set, @@ -129,6 +132,8 @@ unsigned int packet_get_int(void); * must have been initialized before this call. */ void packet_get_bignum(BIGNUM * value, int *length_ptr); +void packet_get_bignum2(BIGNUM * value, int *length_ptr); +char *packet_get_raw(int *length_ptr); /* * Returns a string from the packet data. The string is allocated using |