📄 ssh.c
字号:
/*
* SSH backend.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <signal.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_DHGROUP 0x0001
#define SSH2_PKTCTX_DHGEX 0x0002
#define SSH2_PKTCTX_KEX_MASK 0x000F
#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,
"host not allowed to connect",
"protocol error",
"key exchange failed",
"host authentication failed",
"MAC error",
"compression error",
"service not available",
"protocol version not supported",
"host key not verifiable",
"connection lost",
"by application",
"too many connections",
"auth cancelled by user",
"no more auth methods available",
"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_REKEY 64
#define BUG_SSH2_PK_SESSIONID 128
/*
* Codes for terminal modes.
* Most of these are the same in SSH-1 and SSH-2.
* This list is derived from draft-ietf-secsh-connect-25 and
* SSH-1 RFC-1.2.31.
*/
static const struct {
const char* const mode;
int opcode;
enum { TTY_OP_CHAR, TTY_OP_BOOL } type;
} ssh_ttymodes[] = {
/* "V" prefix discarded for special characters relative to SSH specs */
{ "INTR", 1, TTY_OP_CHAR },
{ "QUIT", 2, TTY_OP_CHAR },
{ "ERASE", 3, TTY_OP_CHAR },
{ "KILL", 4, TTY_OP_CHAR },
{ "EOF", 5, TTY_OP_CHAR },
{ "EOL", 6, TTY_OP_CHAR },
{ "EOL2", 7, TTY_OP_CHAR },
{ "START", 8, TTY_OP_CHAR },
{ "STOP", 9, TTY_OP_CHAR },
{ "SUSP", 10, TTY_OP_CHAR },
{ "DSUSP", 11, TTY_OP_CHAR },
{ "REPRINT", 12, TTY_OP_CHAR },
{ "WERASE", 13, TTY_OP_CHAR },
{ "LNEXT", 14, TTY_OP_CHAR },
{ "FLUSH", 15, TTY_OP_CHAR },
{ "SWTCH", 16, TTY_OP_CHAR },
{ "STATUS", 17, TTY_OP_CHAR },
{ "DISCARD", 18, TTY_OP_CHAR },
{ "IGNPAR", 30, TTY_OP_BOOL },
{ "PARMRK", 31, TTY_OP_BOOL },
{ "INPCK", 32, TTY_OP_BOOL },
{ "ISTRIP", 33, TTY_OP_BOOL },
{ "INLCR", 34, TTY_OP_BOOL },
{ "IGNCR", 35, TTY_OP_BOOL },
{ "ICRNL", 36, TTY_OP_BOOL },
{ "IUCLC", 37, TTY_OP_BOOL },
{ "IXON", 38, TTY_OP_BOOL },
{ "IXANY", 39, TTY_OP_BOOL },
{ "IXOFF", 40, TTY_OP_BOOL },
{ "IMAXBEL", 41, TTY_OP_BOOL },
{ "ISIG", 50, TTY_OP_BOOL },
{ "ICANON", 51, TTY_OP_BOOL },
{ "XCASE", 52, TTY_OP_BOOL },
{ "ECHO", 53, TTY_OP_BOOL },
{ "ECHOE", 54, TTY_OP_BOOL },
{ "ECHOK", 55, TTY_OP_BOOL },
{ "ECHONL", 56, TTY_OP_BOOL },
{ "NOFLSH", 57, TTY_OP_BOOL },
{ "TOSTOP", 58, TTY_OP_BOOL },
{ "IEXTEN", 59, TTY_OP_BOOL },
{ "ECHOCTL", 60, TTY_OP_BOOL },
{ "ECHOKE", 61, TTY_OP_BOOL },
{ "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */
{ "OPOST", 70, TTY_OP_BOOL },
{ "OLCUC", 71, TTY_OP_BOOL },
{ "ONLCR", 72, TTY_OP_BOOL },
{ "OCRNL", 73, TTY_OP_BOOL },
{ "ONOCR", 74, TTY_OP_BOOL },
{ "ONLRET", 75, TTY_OP_BOOL },
{ "CS7", 90, TTY_OP_BOOL },
{ "CS8", 91, TTY_OP_BOOL },
{ "PARENB", 92, TTY_OP_BOOL },
{ "PARODD", 93, TTY_OP_BOOL }
};
/* Miscellaneous other tty-related constants. */
#define SSH_TTY_OP_END 0
/* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */
#define SSH1_TTY_OP_ISPEED 192
#define SSH1_TTY_OP_OSPEED 193
#define SSH2_TTY_OP_ISPEED 128
#define SSH2_TTY_OP_OSPEED 129
/* Helper functions for parsing tty-related config. */
static unsigned int ssh_tty_parse_specchar(char *s)
{
unsigned int ret;
if (*s) {
char *next = NULL;
ret = ctrlparse(s, &next);
if (!next) ret = s[0];
} else {
ret = 255; /* special value meaning "don't set" */
}
return ret;
}
static unsigned int ssh_tty_parse_boolean(char *s)
{
if (stricmp(s, "yes") == 0 ||
stricmp(s, "on") == 0 ||
stricmp(s, "true") == 0 ||
stricmp(s, "+") == 0)
return 1; /* true */
else if (stricmp(s, "no") == 0 ||
stricmp(s, "off") == 0 ||
stricmp(s, "false") == 0 ||
stricmp(s, "-") == 0)
return 0; /* false */
else
return (atoi(s) != 0);
}
#define translate(x) if (type == x) return #x
#define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #x
static 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_DHGROUP);
translatec(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
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
/* 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -