Commit 1d560ceb authored by Niels Möller's avatar Niels Möller
Browse files

Work in progress.

Rev: src/abstract_io.h:1.28
Rev: src/blocking_write.c:1.13
Rev: src/channel.c:1.49
Rev: src/channel.h:1.39
Rev: src/channel_commands.c:1.11
Rev: src/channel_commands.h:1.12
Rev: src/client.c:1.69
Rev: src/client_keyexchange.c:1.29
Rev: src/connection.c:1.36
Rev: src/connection.h:1.32
Rev: src/connection_commands.c:1.8
Rev: src/exception.h:1.2
Rev: src/io.c:1.67
Rev: src/io.h:1.40
Rev: src/io_commands.c:1.16
Rev: src/lsh.c:1.65
Rev: src/read_data.c:1.20
Rev: src/read_data.h:1.8
Rev: src/read_packet.c:1.38
parent 527ac306
......@@ -71,7 +71,7 @@
;; make sure that handler is not called again.
UINT32 "UINT32 available" "UINT8 *data")))
;; "struct exception_handler *io")))
"struct exception_handler *e")))
*/
#define READ_HANDLER(h, l, d) ((h)->handler(&(h), (l), (d)))
......
......@@ -32,20 +32,26 @@
(super abstract_write)
(vars
(fd . int)
(write . (pointer (function int int UINT32 "UINT8 *")))))
(write . (pointer (function void
int UINT32 "UINT8 *" "struct exception_handler *e")))))
*/
#include "blocking_write.c.x"
static int do_blocking_write(struct abstract_write *w,
struct lsh_string *packet)
#if 0
static struct io_exception blocking_io_exception =
STATIC_IO_EXCEPTION(EXC_IO_BLOCKING_WRITE, "Blocking write failed");
#endif
static void do_blocking_write(struct abstract_write *w,
struct lsh_string *packet,
struct exception_handler *e)
{
CAST(blocking_write, closure, w);
int success = closure->write(closure->fd, packet->length, packet->data);
lsh_string_free(packet);
closure->write(closure->fd, packet->length, packet->data, e);
return success ? LSH_OK : LSH_FAIL | LSH_DIE;
lsh_string_free(packet);
}
struct abstract_write *make_blocking_write(int fd, int with_nonblocking)
......
This diff is collapsed.
......@@ -60,8 +60,16 @@
(super flow_controlled)
(vars
; Remote channel number
(channel_number simple UINT32)
(channel_number . UINT32)
; Somewhat redundant. Makes it easier to locate
; the channel_table entry for the channel, which
; is needed for deallocating it.
;; (local_number . UINT32)
; Where to pass errors
(e object exception_handler)
; We try to keep the rec_window_size between max_window / 2
; and max_window.
(max_window simple UINT32)
......@@ -93,14 +101,14 @@
; propagate a channel broken message to the other end?
; Type is CHANNEL_DATA or CHANNEL_STDERR_DATA
(receive method int "int type" "struct lsh_string *data")
(receive method void "int type" "struct lsh_string *data")
; Called when we are allowed to send data on the channel.
(send method int)
(send method void)
; Called when the channel is closed
; FIXME: Is this needed for anything?
(close method int)
(close method void)
; Called when eof is received on the channel (or when it is
; closed, whatever happens first).
......@@ -136,13 +144,10 @@
#define CHANNEL_OPEN_FAILURE(s) \
((s)->open_failure((s)))
/* FIXME: Perhaps, this information is better kept in the connection
* object? */
/* GABA:
(class
(name channel_table)
;; (super exception_handler)
(vars
; FIXME: This is relevant only for the server side. It's
; probably better to store this in the connection struct.
......@@ -150,8 +155,8 @@
;; uid_t user; ; Authenticated user
; Channels are indexed by local number
(channels pointer (object ssh_channel) used_channels)
(channels space (object ssh_channel) used_channels)
; Global requests that we support
(global_requests object alist)
; Channel types that we can open
......@@ -161,6 +166,11 @@
; method as is traditionally used for allocation of unix file
; descriptors.
; Channel numbers can be reserved before there is any actual channel
; assigned to them. So the channels table is not enough for keeping track of which
; numbers are in use.
(in_use space UINT8)
(allocated_channels simple UINT32)
(next_channel simple UINT32)
......@@ -187,6 +197,8 @@
))
*/
#define CHANNEL_EXC_HANDLER(c) (&((c)->table.super))
/* SSH_MSG_GLOBAL_REQUEST */
/* GABA:
......@@ -212,11 +224,21 @@
#define GLOBAL_REQUEST(r, c, a, n) ((r)->handler((r), (c), (a), (n)))
/* SSH_MSG_CHANNEL_OPEN */
/* Raised if opening of a channel fails. */
/* GABA:
(class
(name channel_open_exception)
(super exception)
(vars
(error_code . UINT32)))
*/
#if 0
/* Callback function, used to report success or failure for a
* requested channel open. */
/* GABA:
/* ;;GABA:
(class
(name channel_open_callback)
(vars
......@@ -230,19 +252,21 @@
#define CHANNEL_OPEN_CALLBACK(c, ch, e, m, a) \
(c)->response((c), (ch), (e), (m), (a))
#endif
/* GABA:
(class
(name channel_open)
(vars
(handler method int
(handler method void
"struct ssh_connection *connection"
"struct simple_buffer *data"
"struct channel_open_callback *response")))
"struct command_continuation *c"
"struct exception_handler *e")))
*/
#define CHANNEL_OPEN(o, c, d, n) \
((o)->handler((o), (c), (d), (n)))
#define CHANNEL_OPEN(o, c, d, r, e) \
((o)->handler((o), (c), (d), (r), (e)))
/* SSH_MSG_CHANNEL_REQUEST */
/* GABA:
......
......@@ -35,10 +35,10 @@
#include <assert.h>
int do_channel_open_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
void do_channel_open_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
{
CAST_SUBTYPE(channel_open_command, self, s);
CAST(ssh_connection, connection, x);
......@@ -49,18 +49,22 @@ int do_channel_open_command(struct command *s,
{
/* Probably, we have run out of channel numbers. */
werror("do_channel_open_command: NEW_CHANNEL failed\n");
return EXCEPTION_RAISE(e, &dummy_exception);
EXCEPTION_RAISE(e, &dummy_exception);
}
else
{
channel->open_continuation = c;
C_WRITE(connection, request);
}
channel->open_continuation = c;
return A_WRITE(connection->write, request);
}
int do_channel_request_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
/* FIXME: Where should we use the passed in exception handler, and when should we use the one
* in the connection struct? */
void do_channel_request_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
{
CAST_SUBTYPE(channel_request_command, self, s);
CAST_SUBTYPE(ssh_channel, channel, x);
......@@ -72,13 +76,13 @@ int do_channel_request_command(struct command *s,
object_queue_add_tail(&channel->pending_requests,
&make_command_context(c, e)->super);
return A_WRITE(channel->write, request);
A_WRITE(channel->write, request, e);
}
int do_channel_global_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
void do_channel_global_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
{
CAST_SUBTYPE(global_request_command, self, s);
CAST_SUBTYPE(ssh_connection, connection, x);
......@@ -90,7 +94,7 @@ int do_channel_global_command(struct command *s,
object_queue_add_tail(&connection->channels->pending_global_requests,
&make_command_context(c, e)->super);
return A_WRITE(connection->write, request);
C_WRITE(connection, request);
}
struct lsh_object *
......@@ -147,7 +151,7 @@ do_install_channel_open_handler(struct collect_info_2 *info,
(handler object global_request)))
*/
static int
static void
do_install_fix_global_request_handler(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
......@@ -162,7 +166,7 @@ do_install_fix_global_request_handler(struct command *s,
self->name,
self->handler);
return COMMAND_RETURN(c, x);
COMMAND_RETURN(c, x);
}
struct command *
......@@ -190,7 +194,7 @@ make_install_fix_global_request_handler(UINT32 name,
(handler object channel_open)))
*/
static int
static void
do_install_fix_channel_open_handler(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
......@@ -205,7 +209,7 @@ do_install_fix_channel_open_handler(struct command *s,
self->name,
self->handler);
return COMMAND_RETURN(c, x);
COMMAND_RETURN(c, x);
}
struct command *
......
......@@ -49,7 +49,7 @@
#define NEW_CHANNEL(s, c,r) ((s)->new_channel((s), (c), (r)))
int do_channel_open_command(struct command *s,
void do_channel_open_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e);
......@@ -71,7 +71,7 @@ int do_channel_open_command(struct command *s,
#define FORMAT_CHANNEL_REQUEST(r, c, w) \
((r)->format_request((r), (c), (w)))
int do_channel_request_command(struct command *s,
void do_channel_request_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e);
......@@ -89,10 +89,10 @@ int do_channel_request_command(struct command *s,
#define FORMAT_GLOBAL_REQUEST(r, conn, c) \
((r)->format_request((r), (conn), (c)))
int do_channel_global_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e);
void do_channel_global_command(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e);
struct command *
make_install_global_request_handler(UINT32 name,
......
......@@ -66,9 +66,10 @@
(e object exception_handler)))
*/
static int do_accept_service(struct packet_handler *c,
struct ssh_connection *connection,
struct lsh_string *packet)
static void
do_accept_service(struct packet_handler *c,
struct ssh_connection *connection,
struct lsh_string *packet)
{
CAST(accept_service_handler, closure, c);
......@@ -87,12 +88,13 @@ static int do_accept_service(struct packet_handler *c,
lsh_string_free(packet);
connection->dispatch[SSH_MSG_SERVICE_ACCEPT] = connection->fail;
return COMMAND_RETURN(closure->c, connection);
COMMAND_RETURN(closure->c, connection);
}
else
EXCEPTION_RAISE(closure->e,
make_protocol_exception(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_SERVICE_ACCEPT message"));
lsh_string_free(packet);
return EXCEPTION_RAISE(closure->e,
make_protocol_exception("Invalid SSH_MSG_SERVICE_ACCEPT message"));
}
struct packet_handler *
......@@ -119,10 +121,11 @@ make_accept_service_handler(int service,
;; (service object ssh_service)))
*/
static int do_request_service(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
static void
do_request_service(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e)
{
CAST(request_service, self, s);
CAST(ssh_connection, connection, x);
......@@ -130,8 +133,8 @@ static int do_request_service(struct command *s,
connection->dispatch[SSH_MSG_SERVICE_ACCEPT]
= make_accept_service_handler(self->service, c, e);
return A_WRITE(connection->write,
format_service_request(self->service));
C_WRITE(connection,
format_service_request(self->service));
}
struct command *make_request_service(int service)
......@@ -320,32 +323,33 @@ struct channel_request *make_handle_exit_signal(int *exit_status)
}
/* Receive channel data */
static int do_receive(struct ssh_channel *c,
int type, struct lsh_string *data)
static void
do_receive(struct ssh_channel *c,
int type, struct lsh_string *data)
{
CAST(client_session, closure, c);
switch(type)
{
case CHANNEL_DATA:
return A_WRITE(&closure->out->buffer->super, data);
A_WRITE(&closure->out->buffer->super, data, c->e);
break;
case CHANNEL_STDERR_DATA:
return A_WRITE(&closure->err->buffer->super, data);
A_WRITE(&closure->err->buffer->super, data, c->e);
break;
default:
fatal("Internal error!\n");
}
}
/* We may send more data */
static int do_send(struct ssh_channel *c)
static void do_send(struct ssh_channel *c)
{
CAST(client_session, closure, c);
assert(closure->in->super.read);
assert(closure->in->handler);
closure->in->super.want_read = 1;
return LSH_OK | LSH_GOON;
closure->in->super.want_read = 1;
}
/* We have a remote shell */
......@@ -373,7 +377,7 @@ static int do_client_io(struct command *s UNUSED,
session->out->super.close_callback
= session->err->super.close_callback = make_channel_close(channel);
session->in->handler = make_channel_read_data(channel);
session->in->super.read = make_channel_read_data(channel);
channel->send = do_send;
ALIST_SET(channel->request_types, ATOM_EXIT_STATUS,
......
......@@ -91,7 +91,8 @@ static int do_handle_dh_reply(struct packet_handler *c,
/* Key exchange successful! Send a newkeys message, and install a
* handler for receiving the newkeys message. */
res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS),
connection->e);
if (LSH_CLOSEDP(res))
return res;
......
......@@ -25,6 +25,7 @@
#include "debug.h"
#include "encrypt.h"
#include "exception.h"
#include "format.h"
#include "disconnect.h"
#include "keyexchange.h"
......@@ -39,6 +40,8 @@
#include "connection.h.x"
#undef GABA_DEFINE
#include "connection.c.x"
static const char *packet_types[0x100] =
#include "packet_types.h"
;
......@@ -151,6 +154,47 @@ struct packet_handler *make_unimplemented_handler(void)
return res;
}
/* GABA:
(class
(connection_exception_handler)
(super exception_frame)
(vars
(connection object connection)))
*/
static void
do_connection_exception(struct exception_handler *s,
struct exception *e)
{
CAST(connection_exception_handler, self, s);
switch (e->type)
{
case EXC_PROTOCOL:
{
CAST_SUBTYPE(protocol_exception, exc, e);
if (exc->reason)
C_WRITE(self->connection, format_disconnect(exc->reason, exc->super.msg, ""));
EXCEPTION_RAISE(self->super.parent, &exception_finish_read);
}
break;
default:
EXCEPTION_RAISE(self->super.parent, e);
}
}
struct exception_handler *
make_connection_exception_handler(struct connection *connection,
struct exception_handler *parent)
{
NEW(connection_exception_handler, self);
self->connection = connection;
self->super.parent = parent;
self->super.raise = do_connection_exception;
return &self->super;
}
struct ssh_connection *make_ssh_connection(struct command_continuation *c)
{
int i;
......@@ -235,7 +279,8 @@ struct ssh_connection *make_ssh_connection(struct command_continuation *c)
void connection_init_io(struct ssh_connection *connection,
struct abstract_write *raw,
struct randomness *r)
struct randomness *r,
struct exception_handler *e)
{
/* Initialize i/o hooks */
connection->raw = raw;
......@@ -247,6 +292,10 @@ void connection_init_io(struct ssh_connection *connection,
connection
);
/* Exception handler that sends a proper disconnect message on protocol errors */
connection->e = make_connection_exception_handler(connection, e);
/* Initial encryption state */
connection->send_crypto = connection->rec_crypto = NULL;
connection->send_mac = connection->rec_mac = NULL;
connection->send_compress = connection->rec_compress = NULL;
......
......@@ -44,7 +44,7 @@ struct ssh_connection;
(class
(name packet_handler)
(vars
(handler method int
(handler method void
"struct ssh_connection *connection"
"struct lsh_string *packet")))
*/
......@@ -60,6 +60,11 @@ struct ssh_connection;
(name ssh_connection)
(super abstract_write)
(vars
; Where to pass errors
; FIXME: Is this the right place, or should the exception handler be passed
; to each packet handler?
(e object exception_handler)
; Sent and received version strings
;;(client_version string)
;;(server_version string)
......@@ -112,11 +117,14 @@ struct ssh_connection;
))
*/
#define C_WRITE(c, s) A_WRITE((c)->write, (s), (c)->e)
struct ssh_connection *make_ssh_connection(struct command_continuation *c);
void connection_init_io(struct ssh_connection *connection,
struct abstract_write *raw,
struct randomness *r);
struct randomness *r,
struct exception_handler *e);
struct packet_handler *make_fail_handler(void);
struct packet_handler *make_unimplemented_handler(void);
......
......@@ -219,7 +219,7 @@ make_connection_read_line(struct ssh_connection *connection, int mode,
static int do_connection(struct command *s,
struct lsh_object *x,
struct command_continuation *c,
struct exception_handler *e UNUSED)
struct exception_handler *e)
{
CAST(connection_command, self, s);
CAST(io_fd, fd, x);
......@@ -258,6 +258,14 @@ static int do_connection(struct command *s,
fatal("do_connection: Internal error\n");
}
/* Installing the right exception handler is a little tricky. The
* passed in handler is typically the top-level handler provided by
* lsh.c or lshd.c. On top of this, we add the io_exception_handler
* which takes care of EXC_FINISH_READ exceptions and closes the
* connection's socket. And on top of this, we have a
* connection_exception handler, which takes care of EXC_PROTOCOL
* exceptions, sends a disconnect message, and then raises an
* EXC_FINISH_READ exception. */
connection_init_io
(connection,
&io_read_write(fd,
......@@ -266,7 +274,8 @@ static int do_connection(struct command *s,
self->block_size,
make_connection_close_handler(connection))
->buffer->super,
self->random);
self->random,
make_io_exception_handler(fd, e));
connection->versions[self->mode] = version;
connection->kexinits[self->mode] = MAKE_KEXINIT(self->init);
......
......@@ -33,14 +33,15 @@
(name exception)
(vars
(type . UINT32)
(name . "const char *")))
(msg . "const char *")))
*/
/* GABA:
(class
(name exception_handler)
(vars
(raise method void "const struct exception *")))
(raise method void "const struct exception *")
(parent object exception_handler)))
*/
#define EXCEPTION_RAISE(h, e) ((h)->raise((h), (e)))
......@@ -61,9 +62,11 @@
#define EXC_IO 0x2000
#define EXC_CONNECT 0x2001
#define EXC_RESOLVE 0x2002
#define EXC_IO_BLOCKING_WRITE 0x2003
/* Not really an error */
#define EXC_READ_EOF 0x2003
/* Not really errors */
/* EOF was read */
#define EXC_IO_EOF 0x2003
/* Authorization errors */
#define EXC_AUTH 0x4000
......@@ -77,10 +80,18 @@
/* Use subtypes for the different error codes? */
#define EXC_CHANNEL_OPEN 0x8003
/* Closing down things */
#define EXC_FINISH 0x10000
/* Close a channel */
#define EXC_FINISH_CHANNEL 0x10001
/* Stop reading on some fd */
#define EXC_FINISH_READ 0x10002
extern struct exception_handler default_exception_handler;
extern struct exception dummy_exception;
/* GABA:
/* ;;GABA:
(class
(name exception_frame)
(super exception_handler)
......@@ -110,5 +121,4 @@ make_protocol_exception(UINT32 reason, const char *msg);
#define STATIC_PROTOCOL_EXCEPTION(reason, msg) \
{ { STATIC_HEADER, EXC_PROTOCOL, (msg) }, (reason) }
#endif /* LSH_EXCEPTION_H_INCLUDED */