#ifndef _BPP_H_98d9d7f0_ #define _BPP_H_98d9d7f0_ /* This file is in the public domain. */ /* * BPP stands for Binary Packet Protocol. The code for it is tightly * bound up with the code for the layers of protocol below the channel * layer; this file includes definitions for those layers as well. * * The BPP and LAYER types are fairly central; a lot of data flow * funnels thorugh them. */ /* * A BPP collects together information about the lower layers of the * protocol, such as the algorithms negotiated. There is only one of * these, since we don't support multiple connections per process. * * A LAYER corresponds to one of the layers of protocol below the * channel layer. On input, each LAYER receives packets from the * layer below it, handles those for its own layer, and passes the * rest along to the layer above it; on output, the data flow * directions are reversed, with each layer managing its own protocol, * passing packets through from the layer above (unless it's not ready * to yet, in which case it buffers them - for example, the user * authentication layer does not pass along packets from the channel * layer until user authentication has succeeded). * * A LAYERDESC summarizes the compile-time information about a layer. * (LAYER holds run-time information.) * * An ABORTCB represents a callback to be made if/when the BPP is * aborted, ie, shut down due to a fatal error. ABORTCBs are called * in LIFO order; the last-added callback is the first one called. * * None of this stuff is used by a connection sharing client; * connection sharing works by substituting the sharing connection for * the layers under the channel interface, so there is no LAYER or BPP * involved. (The connection-sharing *server*, on the other hand, * uses LAYERs and a BPP to support both its own channel interface and * the glue layer to the sharing connections.) */ typedef struct bpp BPP; typedef struct layer LAYER; typedef struct layerdesc LAYERDESC; typedef struct abortcb ABORTCB; #include "oq.h" #include "str.h" #include "algs.h" #include "params.h" /* * States for state machine that reads version strings. */ typedef enum { SVS_ATNL = 1, /* Beginning new line */ SVS_GOT_S, /* Saw "S" */ SVS_GOT_SS, /* Saw "SS" */ SVS_GOT_SSH, /* Saw "SSH" */ SVS_GOT_SSH_, /* Saw "SSH-", collecting string */ SVS_GOT_CR, /* Saw CR */ SVS_FLUSHING /* Flushing uninteresting stuff */ } SVS_STATE; /* * The "write" direction means from us to the network; the "read" * direction is from the network to us. The algorithm members are * [rw]_{enc,comp,etc...}{,state}. The first part gives the * direction, the second the kind of algorithm (per the algorithm * type abbreviations in algs.h), and the third is nothing for the * algorithm pointer and "state" for the algorithm's state pointer * (which is opaque to us). */ struct bpp { int fd; /* File descriptor of underlying connection */ int id; /* ID of poll registration */ char *peer_text; /* Printable representation of peer address */ int noreads; /* Boolean: not interested in more input */ ENCALG *w_enc; /* Algorithm pointers and state, */ void *w_encstate; /* following the above schema, up to... */ ENCALG *r_enc; void *r_encstate; COMPALG *w_comp; void *w_compstate; COMPALG *r_comp; void *r_compstate; MACALG *w_mac; void *w_macstate; MACALG *r_mac; void *r_macstate; /* ...here (end of stuff per above schema). */ KEXALG *kex; /* Key-exchange algorithm */ HKALG *hk; /* Host key verification algorithm */ STR K_S; /* Server's host key */ void *kex_k; /* K from key exchange, pointer */ int kex_klen; /* K from key exchange, length */ void *kex_h; /* H from key exchange, pointer */ int kex_hlen; /* H from key exchange, length */ HASHALG *kex_hash; /* HASH from key exchange */ void *sessid; /* Session ID from key exchange, pointer */ int sessidlen; /* Session ID from key exchange, length */ unsigned int w_seq; /* Last packet sequence number, write */ unsigned int r_seq; /* Last packet sequence number, read */ void *hashbuf; /* Buffer for kex_hash output */ LAYER *toplayer; /* Topmost LAYER (so far) */ LAYER *botlayer; /* Bottommost LAYER */ int serverp; /* Boolean: are we server? */ char *lcl_version; /* Our version string, points to [cs]_version */ int *lcl_vlen; /* Our version length, points to [cs]_vlen */ char *rem_version; /* Peer version string, points to [cs]_version */ int *rem_vlen; /* Peer version length, points to [cs]_vlen */ char c_version[SSH_MAX_VERSION_LEN]; /* Client version string */ int c_vlen; /* Client version string length */ char s_version[SSH_MAX_VERSION_LEN]; /* Server version string */ int s_vlen; /* Server version string length */ union { struct { /* Used when reading version strings */ SVS_STATE state; /* State for state machine */ } svs; struct { /* Used when reading packets */ int ril; /* "raw input length": bytes accumulated */ int riw; /* "raw input want": point at which we do stuff */ int rit; /* "raw input total": riw + MAC length */ int pay; /* payload length */ } pkt; } ; void *c_kexinit_payload; /* Client's KEXINIT message payload, pointer */ int c_kexinit_paylen; /* Client's KEXINIT message payload, length */ void *s_kexinit_payload; /* Server's KEXINIT message payload, pointer */ int s_kexinit_paylen; /* Server's KEXINIT message payload, length */ int ipkts_to_rekey; /* Input packets left before rekeying */ int opkts_to_rekey; /* Output packets left before rekeying */ int ibytes_to_rekey; /* Input bytes left before rekeying */ int obytes_to_rekey; /* Output bytes left before rekeying */ int want_rekey; /* We want to rekey */ void (*input)(BPP *, const void *, int); /* Lowest-level input handler */ OQ output; /* Lowest-level output data queue */ unsigned char rawipkt[SSH_MAX_PACKET_LEN]; /* "Raw" input packet: decrypted but compressed */ unsigned char ipkt[SSH_MAX_PAYLOAD_LEN]; /* Input packet: after decompression */ int iplen; /* Input packet length (of ipkt) */ unsigned char rawopkt[SSH_MAX_PAYLOAD_LEN]; /* "Raw" output packet: compressed but unencrypted */ unsigned char opkt[SSH_MAX_PACKET_LEN]; /* Output packet: not yet compressed */ int oplen; /* Output packet length (of opkt) */ ABORTCB *abortcb; /* Stack of ABORTCBs (see above) */ } ; /* * The .id member exists so that an abort callback can be manipulated * (eg, unestablished) after it's established. */ struct abortcb { ABORTCB *link; /* Link in the stack rooted at BPP.abortcb */ int id; /* ID */ void (*fn)(void *); /* Callback function */ void *arg; /* Arg to .fn */ } ; /* * For .ipkt and .opkt, the packet itself lives in the BPP. */ struct layer { BPP *b; /* The BPP it's for */ void (*ipkt)(LAYER *, void *); /* Input a packet (ie, pass up from below) */ void (*opkt)(LAYER *, void *); /* Output a packet (ie, pass down from above) */ void *arg; /* Cookie to .ipkt and .opkt */ LAYER *above; /* Next layer above, nil if top */ LAYER *below; /* Next layer below, nil if bottom */ const LAYERDESC *desc;/* LAYERDESC for this layer */ } ; struct layerdesc { void *(*init)(LAYER *); /* Initialize the LAYER */ void (*ifn)(LAYER *, void *); /* ipkt function, or nil to use bypass_i */ void (*ofn)(LAYER *, void *); /* opkt function, or nil to use bypass_o */ } ; /* * disconn_layer is the LAYER at which disconnect messages are * generated. (They aren't generated by the LAYER that detects them * because they might be blocked by a lower layer that isn't ready to * pass packets yet.) */ extern LAYER *disconn_layer; /* * External interface to the BPP code. */ /* * Pass an input packet to the layer above a given layer. Called when * a layer sees an input packet that's not its own. */ extern void above_ipkt(LAYER *); /* * Pass an output packet to the layer below a given layer. Called when * a layer sees an output packet that's not its own. */ extern void below_opkt(LAYER *); /* * Send a disconnect. Args: * * reason * Reason code (one of the SSH_DISCONNECT_* values). * desc * desclen * The human-readable description string (pointer and * length). * lang * langlen * The language string (pointer and length); this will * usually be zero-length. * * If the length fields are -1, strlen of the corresponding pointer is * used instead. */ extern void send_disconnect(int, const void *, int, const void *, int); /* * Tell a BPP to rekey. */ extern void set_rekey(BPP *); /* * Set up a BPP. The int is a boolean, true for server operation and * false for client operation. */ extern void bpp_setup(BPP *, int); /* * Send our version string. */ extern void sendversion(BPP *); /* * Push a new LAYER on top of the layer stack. Returns the LAYER. */ extern LAYER *push_layer(BPP *, const LAYERDESC *); /* * Do any add_poll_fd() and/or add_block_fn() calls the BPP wants. */ extern void bpp_add_poll(BPP *); /* * Called when no more input should be read from the BPP. */ extern void bpp_done_reading(BPP *); /* * Return a text form of the peer's address. Note that it does not * take a BPP * argument; this routine is designed around the * assumption (currently true) that there will always be exactly one * BPP in use. */ extern const char *bpp_peer_text(void); /* * Add an abort callback. The third arg is merely saved and passed to * the second arg if the callback is done. The returned value is an * opaque handle value. */ extern int bpp_add_abort(BPP *, void (*)(void *), void *); /* * Delete an abort callback, given its handle value. */ extern void bpp_del_abort(BPP *, int); /* * Abort the BPP. This really should take a BPP *, but it is called * from some places - such as deep in compression code - where no BPP * is readily available. */ extern void abort_bpp(void); /* * Layers provided by bpp.c. * * layer_base is the bottommost layer. It passes input packets up, * regardless of content; and output packets, it sends out the * connection, never passing them down (since there is no "down"). * * layer_d_i_d is responsible for handling SSH_MSG_DISCONNECT, * SSH_MSG_IGNORE, and SSH_MSG_DEBUG on input. All other packets are * passed up-stack; all output packets are always passed down-stack. * * layer_catchall is the topmost layer. It never receives output * packets from above, since there is no "above" for it, and input * packets provoke complain-and-exit (because all packets should be * consumed by lower layers). */ extern LAYERDESC layer_base; extern LAYERDESC layer_d_i_d; extern LAYERDESC layer_catchall; #endif