/* $Id: ssh_event.h,v 1.30 2001/02/11 03:35:12 tls Exp $ */ /* * Copyright (c) 2000, 2001 Andrew Brown, Eric Haszlakiewicz, * Thor Lancelot Simon, and Jason R. Thorpe. * 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. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. */ #ifndef _SSH_EVENT_H #define _SSH_EVENT_H #define SSH_THREAD_RECV 0 #define SSH_THREAD_SEND 1 #define SSH_MAX_EVENT_SIZE (512) struct ssh_event { int event_type; u_int8_t event_data[SSH_MAX_EVENT_SIZE]; }; /* * Structure for SSH_EVENT_SEND (send a packet) * Followed by dlen bytes of data. */ struct ssh_ev_send { int dlen; u_int8_t data[1]; }; #define SSH_MAX_EV_SEND_DATA (SSH_MAX_EVENT_SIZE - sizeof(struct ssh_ev_send)) /* * EXITSTATUS: * Send exitstatus * * For v1 this event causes the sendThread to close the file * descriptor(s) associated with the command/shell. * It then sends the supplied EXITSTATUS packet. * * For v2 this event is undefined. * * This event uses the ssh_ev_send structure. */ /* * INIT_COMPRESSION: * Starts compression. Take a single int32 in the event_data. */ /* * MAX_PACKET_SIZE: * Sets maximum packet size. * Takes a single int32 in the event_data. * sendThread should send SUCCESS upon receiving this. */ /* * CHANNEL_CLOSE: * Close a channel. * For v1 this event is currently undefined. * * For v2 this message may be send twice. * Case 1: We initiate * recvThread sends CHANNEL_CLOSE event with initiate set. * sendThread marks fd as closing and sends CHANNEL_CLOSE message. * recvThread receives CHANNEL_CLOSE message and sends CHANNEL_CLOSE event * sendThread frees the channel number. * * Case 2: Other side initiates * recvThread receives CHANNEL_CLOSE message and sends CHANNEL_CLOSE event. * sendThread sends CHANNEL_CLOSE message and frees channel number. */ struct ssh_ev_channel_close { u_int32_t channel_id; int initiate; }; /* * CHANNEL_OPEN: * */ struct ssh_ev_channel_open { enum ssh_channel_types channel_type; u_int32_t channel_id; u_int32_t remote_id; u_int32_t initial_window_size; u_int32_t max_packet_size; }; /* * USERAUTH_OK: * User has fully authenticated. * Takes a single byte which contains the type of success message to send * followed by an asciiz string containing the username. * * v1: SSH_V1_SMSG_SUCCESS * v2: SSH_V2_MSG_USERAUTH_SUCCESS */ struct ssh_ev_ua_ok { u_int8_t msg_type; char username[1]; /* Actually longer */ }; /* * PASSFD * This uses unix domain file descriptor passing to * pass a file descriptor. * It is used to get the file descriptors for exec'd processes * over to the sendThread so it can read from them. * * This message should immediately be followed by a single byte * (doesn't matter what) accompanied by the passed file descriptor. */ struct ssh_ev_passfd { int fd_type; int fd; /* -1 on the event socket, filled in by sys_select */ int channel_id; }; #define FDTYPE_NORMAL 0x01 #define FDTYPE_EXT_STDERR 0x02 /* * INIT_CRYPT: * Tell the send thread to initialize a particular cipher * and start using it. */ struct ssh_ev_init_crypt { int cipher_type; char cipher_data[1]; /* Actually longer */ }; /* * CHANNEL_REQ_SEND: * Issue a channel request * CHANNEL_REQ_EXEC: * Execute a channel request * * A channel request consists of one of several subrequests. * It is associated with a certain channel. * Only certain channels allow certain requests. * The "session" channel is the main one, it must always exist first. */ struct ssh_ev_channel_req { u_int32_t channel; u_int32_t req_type; u_int8_t want_reply; /* boolean */ u_int32_t data_len; char data[1]; /* Actually longer */ }; /* * Format of data for each of these requests. This is the * data than follows the ssh_ev_channel_req type header. * * SSH_CHAN_REQ_pty * u_int32_t size-of-data, data { binstr, 4 int32's, n bytes } * */ enum e_channel_req_types { /* Client to server requests */ SSH_CHAN_REQ_pty, /* "pty-req" NOT USED */ SSH_CHAN_REQ_shell, /* "shell" NOT USED */ SSH_CHAN_REQ_exec, /* "exec" NOT USED */ SSH_CHAN_REQ_x11, /* "x11-req" */ SSH_CHAN_REQ_auth_agent, /* "auth-agent-req" */ SSH_CHAN_REQ_auth_ssh1_agent, /* "auth_ssh1-agent-req" */ SSH_CHAN_REQ_env, /* "env" */ SSH_CHAN_REQ_subsystem, /* "subsystem" */ SSH_CHAN_REQ_window_change, /* "window-change" */ SSH_CHAN_REQ_signal, /* "signal" */ /* Server to client requests */ SSH_CHAN_REQ_exit_status, /* "exit-status" */ SSH_CHAN_REQ_exit_signal, /* "exit-signal" */ SSH_CHAN_REQ_xon_xoff, /* "xon-xoff" */ }; /* * START: * for the client, when the receive thread has decides that it's * through with the initial negotiations (key exchange, * authentication, tty request, etc), it tells the send thread to * start. the send thread already has all the descriptors it * needs...it just needs to "go". */ enum e_ssh_events { SSH_EVENT_NONE = 0, SSH_EVENT_EXITTHREAD, /* Cause the thread to exit XAX */ /* V1 specific */ SSH_EVENT_EXITSTATUS, /* Send exitstatus */ SSH_EVENT_INIT_COMPRESSION, /* Turn on compression */ SSH_EVENT_MAX_PACKET_SIZE, /* Set the max packet size */ /* General use (mostly) */ SSH_EVENT_SEND, /* Send the packet as is (mostly) */ SSH_EVENT_PASSFD, /* Pass a file descriptor */ SSH_EVENT_INIT_CRYPT, /* Turn on encryption */ SSH_EVENT_CHANNEL_CLOSE, /* Close a channel */ SSH_EVENT_CHANNEL_REQ_SEND, /* Send a channel request */ SSH_EVENT_CHANNEL_REQ_EXEC, /* Handle/execute a channel request */ SSH_EVENT_CHANNEL_OPEN, SSH_EVENT_USERAUTH_OK, /* User has fully authenticated */ SSH_EVENT_START, /* Send thread (client) should start */ }; #ifdef SSH_EVENT_STRINGS static const char *event_name[] = { "EVENT_NONE", "EVENT_EXITTHREAD", "EVENT_EXITSTATUS", "EVENT_INIT_COMPRESSION", "EVENT_MAX_PACKET_SIZE", "EVENT_SEND", "EVENT_PASSFD", "EVENT_INIT_CRYPT", "EVENT_CHANNEL_CLOSE", "EVENT_CHANNEL_REQ_SEND", "EVENT_CHANNEL_REQ_EXEC", "EVENT_CHANNEL_OPEN", "EVENT_USERAUTH_OK", "EVENT_START", NULL }; #endif /* SSH_EVENT_STRINGS */ #define EVT_SEND(evp,c) \ do { \ if (ssh_sys_sendevent((c), evp) < 0) \ { \ if ((c)->send_pid == -1) \ SSH_DLOG(1, ("sendThread exited. Exiting recvThread\n")); \ else \ SSH_ERROR("Unable to sendevent"); \ ssh_exit((c), 1, EXIT_NOW); \ } \ } while(0) #define EVT_BUILD_SEND(ev,f) \ do { \ struct ssh_ev_send *evs = (struct ssh_ev_send *)(ev).event_data; \ (ev).event_type = SSH_EVENT_SEND; \ evs->data[0] = (f); \ evs->dlen = 1; \ } while(0) #define EVT_V1_FAILURE(ev) EVT_BUILD_SEND(ev,SSH_V1_SMSG_FAILURE) #define EVT_V1_SUCCESS(ev) EVT_BUILD_SEND(ev,SSH_V1_SMSG_SUCCESS) #define EVT_V2_FAILURE(ev) EVT_BUILD_SEND(ev,SSH_V2_MSG_FAILURE) #define EVT_V2_SUCCESS(ev) EVT_BUILD_SEND(ev,SSH_V2_MSG_SUCCESS) /* The buf_put_binstr will only fail if it tries to realloc, which it can't */ #define EVT_V1_DISCONNECT(ev,c,m) \ do { \ struct ssh_buf evt_buf; \ struct ssh_ev_send *evs = (struct ssh_ev_send *)(ev).event_data; \ (ev).event_type = SSH_EVENT_SEND; \ buf_setbuf(&evt_buf, evs->data, SSH_MAX_EV_SEND_DATA); \ buf_reset(&evt_buf); \ if (buf_put_int8(&evt_buf, SSH_V1_MSG_DISCONNECT) != 0 || \ buf_put_binstr(&evt_buf, (m), strlen(m)) != 0) \ { \ SSH_ERROR("String too long (EVT_V1_DISCONNECT)"); \ ssh_exit((c), 1, EXIT_NOW); \ } \ evs->dlen = buf_alllen(&evt_buf); \ } while (0); #define EVT_V1_DEBUG(ev,c,m) \ do { \ struct ssh_buf evt_buf; \ struct ssh_ev_send *evs = (struct ssh_ev_send *)(ev).event_data; \ (ev).event_type = SSH_EVENT_SEND; \ buf_setbuf(&evt_buf, evs->data, SSH_MAX_EV_SEND_DATA); \ buf_reset(&evt_buf); \ if (buf_put_int8(&evt_buf, SSH_V1_MSG_DEBUG) != 0 || \ buf_put_binstr(&evt_buf, (m), strlen(m)) != 0) \ { \ SSH_ERROR("String too long (EVT_V1_DEBUG)"); \ ssh_exit((c), 1, EXIT_NOW); \ } \ evs->dlen = buf_alllen(&evt_buf); \ } while (0); int ssh_sys_create_eventq(ssh_context_t *context); void ssh_sys_collapse_eventq(ssh_context_t *); int ssh_sys_select(struct ssh_context *, int nfds, fd_set *, fd_set *, fd_set *, struct timeval *, struct ssh_event *); int ssh_sys_sendevent(struct ssh_context *, struct ssh_event *); int ssh_sys_send_fd(ssh_context_t *, int, int, int); int ssh_dispatch_event(ssh_context_t *, struct ssh_event *); #endif /* _SSH_EVENT_H */