📄 ssh.c
字号:
#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <assert.h>#include <limits.h>#include "putty.h"#include "tree234.h"#include "ssh.h"#ifndef FALSE#define FALSE 0#endif#ifndef TRUE#define TRUE 1#endif#define SSH1_MSG_DISCONNECT 1 /* 0x1 */#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */#define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */#define SSH1_CMSG_USER 4 /* 0x4 */#define SSH1_CMSG_AUTH_RSA 6 /* 0x6 */#define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 /* 0x7 */#define SSH1_CMSG_AUTH_RSA_RESPONSE 8 /* 0x8 */#define SSH1_CMSG_AUTH_PASSWORD 9 /* 0x9 */#define SSH1_CMSG_REQUEST_PTY 10 /* 0xa */#define SSH1_CMSG_WINDOW_SIZE 11 /* 0xb */#define SSH1_CMSG_EXEC_SHELL 12 /* 0xc */#define SSH1_CMSG_EXEC_CMD 13 /* 0xd */#define SSH1_SMSG_SUCCESS 14 /* 0xe */#define SSH1_SMSG_FAILURE 15 /* 0xf */#define SSH1_CMSG_STDIN_DATA 16 /* 0x10 */#define SSH1_SMSG_STDOUT_DATA 17 /* 0x11 */#define SSH1_SMSG_STDERR_DATA 18 /* 0x12 */#define SSH1_CMSG_EOF 19 /* 0x13 */#define SSH1_SMSG_EXIT_STATUS 20 /* 0x14 */#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* 0x15 */#define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 /* 0x16 */#define SSH1_MSG_CHANNEL_DATA 23 /* 0x17 */#define SSH1_MSG_CHANNEL_CLOSE 24 /* 0x18 */#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* 0x19 */#define SSH1_SMSG_X11_OPEN 27 /* 0x1b */#define SSH1_CMSG_PORT_FORWARD_REQUEST 28 /* 0x1c */#define SSH1_MSG_PORT_OPEN 29 /* 0x1d */#define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 /* 0x1e */#define SSH1_SMSG_AGENT_OPEN 31 /* 0x1f */#define SSH1_MSG_IGNORE 32 /* 0x20 */#define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */#define SSH1_CMSG_X11_REQUEST_FORWARDING 34 /* 0x22 */#define SSH1_CMSG_AUTH_RHOSTS_RSA 35 /* 0x23 */#define SSH1_MSG_DEBUG 36 /* 0x24 */#define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */#define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */#define SSH1_CMSG_AUTH_CCARD 70 /* 0x46 */#define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 /* 0x47 */#define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 /* 0x48 */#define SSH1_AUTH_TIS 5 /* 0x5 */#define SSH1_AUTH_CCARD 16 /* 0x10 */#define SSH1_PROTOFLAG_SCREEN_NUMBER 1 /* 0x1 *//* Mask for protoflags we will echo back to server if seen */#define SSH1_PROTOFLAGS_SUPPORTED 0 /* 0x1 */#define SSH2_MSG_DISCONNECT 1 /* 0x1 */#define SSH2_MSG_IGNORE 2 /* 0x2 */#define SSH2_MSG_UNIMPLEMENTED 3 /* 0x3 */#define SSH2_MSG_DEBUG 4 /* 0x4 */#define SSH2_MSG_SERVICE_REQUEST 5 /* 0x5 */#define SSH2_MSG_SERVICE_ACCEPT 6 /* 0x6 */#define SSH2_MSG_KEXINIT 20 /* 0x14 */#define SSH2_MSG_NEWKEYS 21 /* 0x15 */#define SSH2_MSG_KEXDH_INIT 30 /* 0x1e */#define SSH2_MSG_KEXDH_REPLY 31 /* 0x1f */#define SSH2_MSG_KEX_DH_GEX_REQUEST 30 /* 0x1e */#define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */#define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */#define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */#define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */#define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */#define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */#define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */#define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */#define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */#define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */#define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */#define SSH2_MSG_CHANNEL_OPEN 90 /* 0x5a */#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 /* 0x5b */#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 /* 0x5c */#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 /* 0x5d */#define SSH2_MSG_CHANNEL_DATA 94 /* 0x5e */#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 /* 0x5f */#define SSH2_MSG_CHANNEL_EOF 96 /* 0x60 */#define SSH2_MSG_CHANNEL_CLOSE 97 /* 0x61 */#define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */#define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */#define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 *//* * Packet type contexts, so that ssh2_pkt_type can correctly decode * the ambiguous type numbers back into the correct type strings. */#define SSH2_PKTCTX_DHGROUP1 0x0001#define SSH2_PKTCTX_DHGEX 0x0002#define SSH2_PKTCTX_PUBLICKEY 0x0010#define SSH2_PKTCTX_PASSWORD 0x0020#define SSH2_PKTCTX_KBDINTER 0x0040#define SSH2_PKTCTX_AUTH_MASK 0x00F0#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 /* 0x1 */#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 /* 0x2 */#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 /* 0x3 */#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 /* 0x4 */#define SSH2_DISCONNECT_MAC_ERROR 5 /* 0x5 */#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 /* 0x6 */#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 /* 0x7 */#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 /* 0x8 */#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 /* 0x9 */#define SSH2_DISCONNECT_CONNECTION_LOST 10 /* 0xa */#define SSH2_DISCONNECT_BY_APPLICATION 11 /* 0xb */#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 /* 0xc */#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 /* 0xd */#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 /* 0xe */#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 /* 0xf */static const char *const ssh2_disconnect_reasons[] = { NULL, "SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT", "SSH_DISCONNECT_PROTOCOL_ERROR", "SSH_DISCONNECT_KEY_EXCHANGE_FAILED", "SSH_DISCONNECT_HOST_AUTHENTICATION_FAILED", "SSH_DISCONNECT_MAC_ERROR", "SSH_DISCONNECT_COMPRESSION_ERROR", "SSH_DISCONNECT_SERVICE_NOT_AVAILABLE", "SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED", "SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE", "SSH_DISCONNECT_CONNECTION_LOST", "SSH_DISCONNECT_BY_APPLICATION", "SSH_DISCONNECT_TOO_MANY_CONNECTIONS", "SSH_DISCONNECT_AUTH_CANCELLED_BY_USER", "SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE", "SSH_DISCONNECT_ILLEGAL_USER_NAME",};#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 /* 0x1 */#define SSH2_OPEN_CONNECT_FAILED 2 /* 0x2 */#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 /* 0x3 */#define SSH2_OPEN_RESOURCE_SHORTAGE 4 /* 0x4 */#define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 *//* * Various remote-bug flags. */#define BUG_CHOKES_ON_SSH1_IGNORE 1#define BUG_SSH2_HMAC 2#define BUG_NEEDS_SSH1_PLAIN_PASSWORD 4#define BUG_CHOKES_ON_RSA 8#define BUG_SSH2_RSA_PADDING 16#define BUG_SSH2_DERIVEKEY 32#define BUG_SSH2_DH_GEX 64#define BUG_SSH2_PK_SESSIONID 128#define translate(x) if (type == x) return #x#define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #xstatic char *ssh1_pkt_type(int type){ translate(SSH1_MSG_DISCONNECT); translate(SSH1_SMSG_PUBLIC_KEY); translate(SSH1_CMSG_SESSION_KEY); translate(SSH1_CMSG_USER); translate(SSH1_CMSG_AUTH_RSA); translate(SSH1_SMSG_AUTH_RSA_CHALLENGE); translate(SSH1_CMSG_AUTH_RSA_RESPONSE); translate(SSH1_CMSG_AUTH_PASSWORD); translate(SSH1_CMSG_REQUEST_PTY); translate(SSH1_CMSG_WINDOW_SIZE); translate(SSH1_CMSG_EXEC_SHELL); translate(SSH1_CMSG_EXEC_CMD); translate(SSH1_SMSG_SUCCESS); translate(SSH1_SMSG_FAILURE); translate(SSH1_CMSG_STDIN_DATA); translate(SSH1_SMSG_STDOUT_DATA); translate(SSH1_SMSG_STDERR_DATA); translate(SSH1_CMSG_EOF); translate(SSH1_SMSG_EXIT_STATUS); translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION); translate(SSH1_MSG_CHANNEL_OPEN_FAILURE); translate(SSH1_MSG_CHANNEL_DATA); translate(SSH1_MSG_CHANNEL_CLOSE); translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION); translate(SSH1_SMSG_X11_OPEN); translate(SSH1_CMSG_PORT_FORWARD_REQUEST); translate(SSH1_MSG_PORT_OPEN); translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING); translate(SSH1_SMSG_AGENT_OPEN); translate(SSH1_MSG_IGNORE); translate(SSH1_CMSG_EXIT_CONFIRMATION); translate(SSH1_CMSG_X11_REQUEST_FORWARDING); translate(SSH1_CMSG_AUTH_RHOSTS_RSA); translate(SSH1_MSG_DEBUG); translate(SSH1_CMSG_REQUEST_COMPRESSION); translate(SSH1_CMSG_AUTH_TIS); translate(SSH1_SMSG_AUTH_TIS_CHALLENGE); translate(SSH1_CMSG_AUTH_TIS_RESPONSE); translate(SSH1_CMSG_AUTH_CCARD); translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE); translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); return "unknown";}static char *ssh2_pkt_type(int pkt_ctx, int type){ translate(SSH2_MSG_DISCONNECT); translate(SSH2_MSG_IGNORE); translate(SSH2_MSG_UNIMPLEMENTED); translate(SSH2_MSG_DEBUG); translate(SSH2_MSG_SERVICE_REQUEST); translate(SSH2_MSG_SERVICE_ACCEPT); translate(SSH2_MSG_KEXINIT); translate(SSH2_MSG_NEWKEYS); translatec(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP1); translatec(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP1); translatec(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX); translatec(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX); translatec(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX); translatec(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX); translate(SSH2_MSG_USERAUTH_REQUEST); translate(SSH2_MSG_USERAUTH_FAILURE); translate(SSH2_MSG_USERAUTH_SUCCESS); translate(SSH2_MSG_USERAUTH_BANNER); translatec(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY); translatec(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD); translatec(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER); translatec(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER); translate(SSH2_MSG_GLOBAL_REQUEST); translate(SSH2_MSG_REQUEST_SUCCESS); translate(SSH2_MSG_REQUEST_FAILURE); translate(SSH2_MSG_CHANNEL_OPEN); translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); translate(SSH2_MSG_CHANNEL_OPEN_FAILURE); translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST); translate(SSH2_MSG_CHANNEL_DATA); translate(SSH2_MSG_CHANNEL_EXTENDED_DATA); translate(SSH2_MSG_CHANNEL_EOF); translate(SSH2_MSG_CHANNEL_CLOSE); translate(SSH2_MSG_CHANNEL_REQUEST); translate(SSH2_MSG_CHANNEL_SUCCESS); translate(SSH2_MSG_CHANNEL_FAILURE); return "unknown";}#undef translate#undef translatec#define GET_32BIT(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 24) | \ ((unsigned long)(unsigned char)(cp)[1] << 16) | \ ((unsigned long)(unsigned char)(cp)[2] << 8) | \ ((unsigned long)(unsigned char)(cp)[3]))#define PUT_32BIT(cp, value) { \ (cp)[0] = (unsigned char)((value) >> 24); \ (cp)[1] = (unsigned char)((value) >> 16); \ (cp)[2] = (unsigned char)((value) >> 8); \ (cp)[3] = (unsigned char)(value); }/* Enumeration values for fields in SSH-1 packets */enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, /* These values are for communicating relevant semantics of * fields to the packet logging code. */ PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA};/* * Coroutine mechanics for the sillier bits of the code. If these * macros look impenetrable to you, you might find it helpful to * read * * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html * * which explains the theory behind these macros. * * In particular, if you are getting `case expression not constant' * errors when building with MS Visual Studio, this is because MS's * Edit and Continue debugging feature causes their compiler to * violate ANSI C. To disable Edit and Continue debugging: * * - right-click ssh.c in the FileView * - click Settings * - select the C/C++ tab and the General category * - under `Debug info:', select anything _other_ than `Program * Database for Edit and Continue'. */#define crBegin(v) { int *crLine = &v; switch(v) { case 0:;#define crState(t) \ struct t *s; \ if (!ssh->t) ssh->t = snew(struct t); \ s = ssh->t;#define crFinish(z) } *crLine = 0; return (z); }#define crFinishV } *crLine = 0; return; }#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;static void ssh2_pkt_init(Ssh, int pkt_type);static void ssh2_pkt_addbool(Ssh, unsigned char value);static void ssh2_pkt_adduint32(Ssh, unsigned long value);static void ssh2_pkt_addstring_start(Ssh);static void ssh2_pkt_addstring_str(Ssh, char *data);static void ssh2_pkt_addstring_data(Ssh, char *data, int len);static void ssh2_pkt_addstring(Ssh, char *data);static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);static void ssh2_pkt_addmp(Ssh, Bignum b);static int ssh2_pkt_construct(Ssh);static void ssh2_pkt_send(Ssh);static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt);static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt);/* * 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 SSH1 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 SSH2 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 SSH2 * channels. */#define SSH1_BUFFER_LIMIT 32768#define SSH_MAX_BACKLOG 32768#define OUR_V2_WINSIZE 16384const static struct ssh_kex *const kex_algs[] = { &ssh_diffiehellman_gex, &ssh_diffiehellman};const static struct ssh_signkey *const hostkey_algs[] = { &ssh_rsa, &ssh_dss };static void *nullmac_make_context(void){ return NULL;}static void nullmac_free_context(void *handle){}static void nullmac_key(void *handle, unsigned char *key){}static void nullmac_generate(void *handle, unsigned char *blk, int len, unsigned long seq){}static int nullmac_verify(void *handle, unsigned char *blk, int len, unsigned long seq){ return 1;}const static struct ssh_mac ssh_mac_none = { nullmac_make_context, nullmac_free_context, nullmac_key, nullmac_generate, nullmac_verify, "none", 0};const static struct ssh_mac *const macs[] = { &ssh_sha1, &ssh_md5, &ssh_mac_none};const static struct ssh_mac *const buggymacs[] = { &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none};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 *const 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 */};/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -