ssh.c
来自「putty」· C语言 代码 · 共 2,015 行 · 第 1/5 页
C
2,015 行
#define crReturn(z) \
do {\
*crLine =__LINE__; return (z); case __LINE__:;\
} while (0)
#define crReturnV \
do {\
*crLine=__LINE__; return; case __LINE__:;\
} while (0)
#define crStop(z) do{ *crLine = 0; return (z); }while(0)
#define crStopV do{ *crLine = 0; return; }while(0)
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
typedef struct ssh_tag *Ssh;
struct Packet;
static struct Packet *ssh1_pkt_init(int pkt_type);
static struct Packet *ssh2_pkt_init(int pkt_type);
static void ssh_pkt_ensure(struct Packet *, int length);
static void ssh_pkt_adddata(struct Packet *, void *data, int len);
static void ssh_pkt_addbyte(struct Packet *, unsigned char value);
static void ssh2_pkt_addbool(struct Packet *, unsigned char value);
static void ssh_pkt_adduint32(struct Packet *, unsigned long value);
static void ssh_pkt_addstring_start(struct Packet *);
static void ssh_pkt_addstring_str(struct Packet *, char *data);
static void ssh_pkt_addstring_data(struct Packet *, char *data, int len);
static void ssh_pkt_addstring(struct Packet *, char *data);
static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);
static void ssh1_pkt_addmp(struct Packet *, Bignum b);
static void ssh2_pkt_addmp(struct Packet *, Bignum b);
static int ssh2_pkt_construct(Ssh, struct Packet *);
static void ssh2_pkt_send(Ssh, struct Packet *);
static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);
static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin);
static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin);
/*
* Buffer management constants. There are several of these for
* various different purposes:
*
* - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
* on a local data stream before we throttle the whole SSH
* connection (in SSH-1 only). Throttling the whole connection is
* pretty drastic so we set this high in the hope it won't
* happen very often.
*
* - SSH_MAX_BACKLOG is the amount of backlog that must build up
* on the SSH connection itself before we defensively throttle
* _all_ local data streams. This is pretty drastic too (though
* thankfully unlikely in SSH-2 since the window mechanism should
* ensure that the server never has any need to throttle its end
* of the connection), so we set this high as well.
*
* - OUR_V2_WINSIZE is the maximum window size we present on SSH-2
* channels.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_MAXPKT 0x4000UL
/* Maximum length of passwords/passphrases (arbitrary) */
#define SSH_MAX_PASSWORD_LEN 100
const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = {
&ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
};
const static struct ssh_mac *buggymacs[] = {
&ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
};
static void *ssh_comp_none_init(void)
{
return NULL;
}
static void ssh_comp_none_cleanup(void *handle)
{
}
static int ssh_comp_none_block(void *handle, unsigned char *block, int len,
unsigned char **outblock, int *outlen)
{
return 0;
}
static int ssh_comp_none_disable(void *handle)
{
return 0;
}
const static struct ssh_compress ssh_comp_none = {
"none",
ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
ssh_comp_none_disable, NULL
};
extern const struct ssh_compress ssh_zlib;
const static struct ssh_compress *compressions[] = {
&ssh_zlib, &ssh_comp_none
};
enum { /* channel types */
CHAN_MAINSESSION,
CHAN_X11,
CHAN_AGENT,
CHAN_SOCKDATA,
CHAN_SOCKDATA_DORMANT /* one the remote hasn't confirmed */
};
/*
* 2-3-4 tree storing channels.
*/
struct ssh_channel {
Ssh ssh; /* pointer back to main context */
unsigned remoteid, localid;
int type;
/* True if we opened this channel but server hasn't confirmed. */
int halfopen;
/*
* In SSH-1, this value contains four bits:
*
* 1 We have sent SSH1_MSG_CHANNEL_CLOSE.
* 2 We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
* 4 We have received SSH1_MSG_CHANNEL_CLOSE.
* 8 We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
*
* A channel is completely finished with when all four bits are set.
*/
int closes;
union {
struct ssh1_data_channel {
int throttling;
} v1;
struct ssh2_data_channel {
bufchain outbuffer;
unsigned remwindow, remmaxpkt;
unsigned locwindow;
} v2;
} v;
union {
struct ssh_agent_channel {
unsigned char *message;
unsigned char msglen[4];
unsigned lensofar, totallen;
} a;
struct ssh_x11_channel {
Socket s;
} x11;
struct ssh_pfd_channel {
Socket s;
} pfd;
} u;
};
/*
* 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2
* use this structure in different ways, reflecting SSH-2's
* altogether saner approach to port forwarding.
*
* In SSH-1, you arrange a remote forwarding by sending the server
* the remote port number, and the local destination host:port.
* When a connection comes in, the server sends you back that
* host:port pair, and you connect to it. This is a ready-made
* security hole if you're not on the ball: a malicious server
* could send you back _any_ host:port pair, so if you trustingly
* connect to the address it gives you then you've just opened the
* entire inside of your corporate network just by connecting
* through it to a dodgy SSH server. Hence, we must store a list of
* host:port pairs we _are_ trying to forward to, and reject a
* connection request from the server if it's not in the list.
*
* In SSH-2, each side of the connection minds its own business and
* doesn't send unnecessary information to the other. You arrange a
* remote forwarding by sending the server just the remote port
* number. When a connection comes in, the server tells you which
* of its ports was connected to; and _you_ have to remember what
* local host:port pair went with that port number.
*
* Hence, in SSH-1 this structure is indexed by destination
* host:port pair, whereas in SSH-2 it is indexed by source port.
*/
struct ssh_portfwd; /* forward declaration */
struct ssh_rportfwd {
unsigned sport, dport;
char dhost[256];
char *sportdesc;
struct ssh_portfwd *pfrec;
};
#define free_rportfwd(pf) ( \
((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) )
/*
* Separately to the rportfwd tree (which is for looking up port
* open requests from the server), a tree of _these_ structures is
* used to keep track of all the currently open port forwardings,
* so that we can reconfigure in mid-session if the user requests
* it.
*/
struct ssh_portfwd {
enum { DESTROY, KEEP, CREATE } status;
int type;
unsigned sport, dport;
char *saddr, *daddr;
char *sserv, *dserv;
struct ssh_rportfwd *remote;
int addressfamily;
void *local;
};
#define free_portfwd(pf) ( \
((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \
sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )
struct Packet {
long length; /* length of `data' actually used */
long forcepad; /* SSH-2: force padding to at least this length */
int type; /* only used for incoming packets */
unsigned long sequence; /* SSH-2 incoming sequence number */
unsigned char *data; /* allocated storage */
unsigned char *body; /* offset of payload within `data' */
long savedpos; /* temporary index into `data' (for strings) */
long maxlen; /* amount of storage allocated for `data' */
long encrypted_len; /* for SSH-2 total-size counting */
/*
* State associated with packet logging
*/
int logmode;
int nblanks;
struct logblank_t *blanks;
};
static void ssh1_protocol(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
static void ssh2_protocol(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
static void ssh1_protocol_setup(Ssh ssh);
static void ssh2_protocol_setup(Ssh ssh);
static void ssh_size(void *handle, int width, int height);
static void ssh_special(void *handle, Telnet_Special);
static int ssh2_try_send(struct ssh_channel *c);
static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len);
static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
static int ssh_sendbuffer(void *handle);
static int ssh_do_close(Ssh ssh, int notify_exit);
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
static int ssh2_pkt_getbool(struct Packet *pkt);
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
static void ssh2_timer(void *ctx, long now);
static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
struct rdpkt1_state_tag {
long len, pad, biglen, to_read;
unsigned long realcrc, gotcrc;
unsigned char *p;
int i;
int chunk;
struct Packet *pktin;
};
struct rdpkt2_state_tag {
long len, pad, payload, packetlen, maclen;
int i;
int cipherblk;
unsigned long incoming_sequence;
struct Packet *pktin;
};
typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);
typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);
struct queued_handler;
struct queued_handler {
int msg1, msg2;
chandler_fn_t handler;
void *ctx;
struct queued_handler *next;
};
struct ssh_tag {
const struct plug_function_table *fn;
/* the above field _must_ be first in the structure */
char *v_c, *v_s;
void *exhash;
Socket s;
void *ldisc;
void *logctx;
unsigned char session_key[32];
int v1_compressing;
int v1_remote_protoflags;
int v1_local_protoflags;
int agentfwd_enabled;
int X11_fwd_enabled;
int remote_bugs;
const struct ssh_cipher *cipher;
void *v1_cipher_ctx;
void *crcda_ctx;
const struct ssh2_cipher *cscipher, *sccipher;
void *cs_cipher_ctx, *sc_cipher_ctx;
const struct ssh_mac *csmac, *scmac;
void *cs_mac_ctx, *sc_mac_ctx;
const struct ssh_compress *cscomp, *sccomp;
void *cs_comp_ctx, *sc_comp_ctx;
const struct ssh_kex *kex;
const struct ssh_signkey *hostkey;
unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN];
int v2_session_id_len;
void *kex_ctx;
char *savedhost;
int savedport;
int send_ok;
int echoing, editing;
void *frontend;
int ospeed, ispeed; /* temporaries */
int term_width, term_height;
tree234 *channels; /* indexed by local id */
struct ssh_channel *mainchan; /* primary session channel */
int ncmode; /* is primary channel direct-tcpip? */
int exitcode;
int close_expected;
int clean_exit;
tree234 *rportfwds, *portfwds;
enum {
SSH_STATE_PREPACKET,
SSH_STATE_BEFORE_SIZE,
SSH_STATE_INTERMED,
SSH_STATE_SESSION,
SSH_STATE_CLOSED
} state;
int size_needed, eof_needed;
struct Packet **queue;
int queuelen, queuesize;
int queueing;
unsigned char *deferred_send_data;
int deferred_len, deferred_size;
/*
* Gross hack: pscp will try to start SFTP but fall back to
* scp1 if that fails. This variable is the means by which
* scp.c can reach into the SSH code and find out which one it
* got.
*/
int fallback_cmd;
bufchain banner; /* accumulates banners during do_ssh2_authconn */
int pkt_ctx;
void *x11auth;
int version;
int v1_throttle_count;
int overall_bufsize;
int throttled_all;
int v1_stdout_throttling;
unsigned long v2_outgoing_sequence;
int ssh1_rdpkt_crstate;
int ssh2_rdpkt_crstate;
int do_ssh_init_crstate;
int ssh_gotdata_crstate;
int do_ssh1_login_crstate;
int do_ssh1_connection_crstate;
int do_ssh2_transport_crstate;
int do_ssh2_authconn_crstate;
void *do_ssh_init_state;
void *do_ssh1_login_state;
void *do_ssh2_transport_state;
void *do_ssh2_authconn_state;
struct rdpkt1_state_tag rdpkt1_state;
struct rdpkt2_state_tag rdpkt2_state;
/* SSH-1 and SSH-2 use this for different things, but both use it */
int protocol_initial_phase_done;
void (*protocol) (Ssh ssh, void *vin, int inlen,
struct Packet *pkt);
struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen);
/*
* We maintain a full _copy_ of a Config structure here, not
* merely a pointer to it. That way, when we're passed a new
* one for reconfiguration, we can check the differences and
* potentially reconfigure port forwardings etc in mid-session.
*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?