Fix broken build by moving implementations to cpp files
[TortoiseGit.git] / src / TortoisePlink / SSH.C
blobbffe27762fe656e730700af3e4470a2aefdcf0aa
1 /*\r
2  * SSH backend.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include <stdarg.h>\r
8 #include <assert.h>\r
9 #include <limits.h>\r
10 #include <signal.h>\r
12 #include "putty.h"\r
13 #include "tree234.h"\r
14 #include "ssh.h"\r
15 #ifndef NO_GSSAPI\r
16 #include "sshgssc.h"\r
17 #include "sshgss.h"\r
18 #endif\r
20 #ifndef FALSE\r
21 #define FALSE 0\r
22 #endif\r
23 #ifndef TRUE\r
24 #define TRUE 1\r
25 #endif\r
27 #define SSH1_MSG_DISCONNECT                       1     /* 0x1 */\r
28 #define SSH1_SMSG_PUBLIC_KEY                      2     /* 0x2 */\r
29 #define SSH1_CMSG_SESSION_KEY                     3     /* 0x3 */\r
30 #define SSH1_CMSG_USER                            4     /* 0x4 */\r
31 #define SSH1_CMSG_AUTH_RSA                        6     /* 0x6 */\r
32 #define SSH1_SMSG_AUTH_RSA_CHALLENGE              7     /* 0x7 */\r
33 #define SSH1_CMSG_AUTH_RSA_RESPONSE               8     /* 0x8 */\r
34 #define SSH1_CMSG_AUTH_PASSWORD                   9     /* 0x9 */\r
35 #define SSH1_CMSG_REQUEST_PTY                     10    /* 0xa */\r
36 #define SSH1_CMSG_WINDOW_SIZE                     11    /* 0xb */\r
37 #define SSH1_CMSG_EXEC_SHELL                      12    /* 0xc */\r
38 #define SSH1_CMSG_EXEC_CMD                        13    /* 0xd */\r
39 #define SSH1_SMSG_SUCCESS                         14    /* 0xe */\r
40 #define SSH1_SMSG_FAILURE                         15    /* 0xf */\r
41 #define SSH1_CMSG_STDIN_DATA                      16    /* 0x10 */\r
42 #define SSH1_SMSG_STDOUT_DATA                     17    /* 0x11 */\r
43 #define SSH1_SMSG_STDERR_DATA                     18    /* 0x12 */\r
44 #define SSH1_CMSG_EOF                             19    /* 0x13 */\r
45 #define SSH1_SMSG_EXIT_STATUS                     20    /* 0x14 */\r
46 #define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION        21    /* 0x15 */\r
47 #define SSH1_MSG_CHANNEL_OPEN_FAILURE             22    /* 0x16 */\r
48 #define SSH1_MSG_CHANNEL_DATA                     23    /* 0x17 */\r
49 #define SSH1_MSG_CHANNEL_CLOSE                    24    /* 0x18 */\r
50 #define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION       25    /* 0x19 */\r
51 #define SSH1_SMSG_X11_OPEN                        27    /* 0x1b */\r
52 #define SSH1_CMSG_PORT_FORWARD_REQUEST            28    /* 0x1c */\r
53 #define SSH1_MSG_PORT_OPEN                        29    /* 0x1d */\r
54 #define SSH1_CMSG_AGENT_REQUEST_FORWARDING        30    /* 0x1e */\r
55 #define SSH1_SMSG_AGENT_OPEN                      31    /* 0x1f */\r
56 #define SSH1_MSG_IGNORE                           32    /* 0x20 */\r
57 #define SSH1_CMSG_EXIT_CONFIRMATION               33    /* 0x21 */\r
58 #define SSH1_CMSG_X11_REQUEST_FORWARDING          34    /* 0x22 */\r
59 #define SSH1_CMSG_AUTH_RHOSTS_RSA                 35    /* 0x23 */\r
60 #define SSH1_MSG_DEBUG                            36    /* 0x24 */\r
61 #define SSH1_CMSG_REQUEST_COMPRESSION             37    /* 0x25 */\r
62 #define SSH1_CMSG_AUTH_TIS                        39    /* 0x27 */\r
63 #define SSH1_SMSG_AUTH_TIS_CHALLENGE              40    /* 0x28 */\r
64 #define SSH1_CMSG_AUTH_TIS_RESPONSE               41    /* 0x29 */\r
65 #define SSH1_CMSG_AUTH_CCARD                      70    /* 0x46 */\r
66 #define SSH1_SMSG_AUTH_CCARD_CHALLENGE            71    /* 0x47 */\r
67 #define SSH1_CMSG_AUTH_CCARD_RESPONSE             72    /* 0x48 */\r
69 #define SSH1_AUTH_RHOSTS                          1     /* 0x1 */\r
70 #define SSH1_AUTH_RSA                             2     /* 0x2 */\r
71 #define SSH1_AUTH_PASSWORD                        3     /* 0x3 */\r
72 #define SSH1_AUTH_RHOSTS_RSA                      4     /* 0x4 */\r
73 #define SSH1_AUTH_TIS                             5     /* 0x5 */\r
74 #define SSH1_AUTH_CCARD                           16    /* 0x10 */\r
76 #define SSH1_PROTOFLAG_SCREEN_NUMBER              1     /* 0x1 */\r
77 /* Mask for protoflags we will echo back to server if seen */\r
78 #define SSH1_PROTOFLAGS_SUPPORTED                 0     /* 0x1 */\r
80 #define SSH2_MSG_DISCONNECT                       1     /* 0x1 */\r
81 #define SSH2_MSG_IGNORE                           2     /* 0x2 */\r
82 #define SSH2_MSG_UNIMPLEMENTED                    3     /* 0x3 */\r
83 #define SSH2_MSG_DEBUG                            4     /* 0x4 */\r
84 #define SSH2_MSG_SERVICE_REQUEST                  5     /* 0x5 */\r
85 #define SSH2_MSG_SERVICE_ACCEPT                   6     /* 0x6 */\r
86 #define SSH2_MSG_KEXINIT                          20    /* 0x14 */\r
87 #define SSH2_MSG_NEWKEYS                          21    /* 0x15 */\r
88 #define SSH2_MSG_KEXDH_INIT                       30    /* 0x1e */\r
89 #define SSH2_MSG_KEXDH_REPLY                      31    /* 0x1f */\r
90 #define SSH2_MSG_KEX_DH_GEX_REQUEST               30    /* 0x1e */\r
91 #define SSH2_MSG_KEX_DH_GEX_GROUP                 31    /* 0x1f */\r
92 #define SSH2_MSG_KEX_DH_GEX_INIT                  32    /* 0x20 */\r
93 #define SSH2_MSG_KEX_DH_GEX_REPLY                 33    /* 0x21 */\r
94 #define SSH2_MSG_KEXRSA_PUBKEY                    30    /* 0x1e */\r
95 #define SSH2_MSG_KEXRSA_SECRET                    31    /* 0x1f */\r
96 #define SSH2_MSG_KEXRSA_DONE                      32    /* 0x20 */\r
97 #define SSH2_MSG_USERAUTH_REQUEST                 50    /* 0x32 */\r
98 #define SSH2_MSG_USERAUTH_FAILURE                 51    /* 0x33 */\r
99 #define SSH2_MSG_USERAUTH_SUCCESS                 52    /* 0x34 */\r
100 #define SSH2_MSG_USERAUTH_BANNER                  53    /* 0x35 */\r
101 #define SSH2_MSG_USERAUTH_PK_OK                   60    /* 0x3c */\r
102 #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ        60    /* 0x3c */\r
103 #define SSH2_MSG_USERAUTH_INFO_REQUEST            60    /* 0x3c */\r
104 #define SSH2_MSG_USERAUTH_INFO_RESPONSE           61    /* 0x3d */\r
105 #define SSH2_MSG_GLOBAL_REQUEST                   80    /* 0x50 */\r
106 #define SSH2_MSG_REQUEST_SUCCESS                  81    /* 0x51 */\r
107 #define SSH2_MSG_REQUEST_FAILURE                  82    /* 0x52 */\r
108 #define SSH2_MSG_CHANNEL_OPEN                     90    /* 0x5a */\r
109 #define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION        91    /* 0x5b */\r
110 #define SSH2_MSG_CHANNEL_OPEN_FAILURE             92    /* 0x5c */\r
111 #define SSH2_MSG_CHANNEL_WINDOW_ADJUST            93    /* 0x5d */\r
112 #define SSH2_MSG_CHANNEL_DATA                     94    /* 0x5e */\r
113 #define SSH2_MSG_CHANNEL_EXTENDED_DATA            95    /* 0x5f */\r
114 #define SSH2_MSG_CHANNEL_EOF                      96    /* 0x60 */\r
115 #define SSH2_MSG_CHANNEL_CLOSE                    97    /* 0x61 */\r
116 #define SSH2_MSG_CHANNEL_REQUEST                  98    /* 0x62 */\r
117 #define SSH2_MSG_CHANNEL_SUCCESS                  99    /* 0x63 */\r
118 #define SSH2_MSG_CHANNEL_FAILURE                  100   /* 0x64 */\r
119 #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE               60\r
120 #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN                  61\r
121 #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE      63\r
122 #define SSH2_MSG_USERAUTH_GSSAPI_ERROR                  64\r
123 #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK                 65\r
124 #define SSH2_MSG_USERAUTH_GSSAPI_MIC                    66\r
126 /*\r
127  * Packet type contexts, so that ssh2_pkt_type can correctly decode\r
128  * the ambiguous type numbers back into the correct type strings.\r
129  */\r
130 typedef enum {\r
131     SSH2_PKTCTX_NOKEX,\r
132     SSH2_PKTCTX_DHGROUP,\r
133     SSH2_PKTCTX_DHGEX,\r
134     SSH2_PKTCTX_RSAKEX\r
135 } Pkt_KCtx;\r
136 typedef enum {\r
137     SSH2_PKTCTX_NOAUTH,\r
138     SSH2_PKTCTX_PUBLICKEY,\r
139     SSH2_PKTCTX_PASSWORD,\r
140     SSH2_PKTCTX_GSSAPI,\r
141     SSH2_PKTCTX_KBDINTER\r
142 } Pkt_ACtx;\r
144 #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1   /* 0x1 */\r
145 #define SSH2_DISCONNECT_PROTOCOL_ERROR            2     /* 0x2 */\r
146 #define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED       3     /* 0x3 */\r
147 #define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4    /* 0x4 */\r
148 #define SSH2_DISCONNECT_MAC_ERROR                 5     /* 0x5 */\r
149 #define SSH2_DISCONNECT_COMPRESSION_ERROR         6     /* 0x6 */\r
150 #define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE     7     /* 0x7 */\r
151 #define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8        /* 0x8 */\r
152 #define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE   9     /* 0x9 */\r
153 #define SSH2_DISCONNECT_CONNECTION_LOST           10    /* 0xa */\r
154 #define SSH2_DISCONNECT_BY_APPLICATION            11    /* 0xb */\r
155 #define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS      12    /* 0xc */\r
156 #define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER    13    /* 0xd */\r
157 #define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14       /* 0xe */\r
158 #define SSH2_DISCONNECT_ILLEGAL_USER_NAME         15    /* 0xf */\r
160 static const char *const ssh2_disconnect_reasons[] = {\r
161     NULL,\r
162     "host not allowed to connect",\r
163     "protocol error",\r
164     "key exchange failed",\r
165     "host authentication failed",\r
166     "MAC error",\r
167     "compression error",\r
168     "service not available",\r
169     "protocol version not supported",\r
170     "host key not verifiable",\r
171     "connection lost",\r
172     "by application",\r
173     "too many connections",\r
174     "auth cancelled by user",\r
175     "no more auth methods available",\r
176     "illegal user name",\r
177 };\r
179 #define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED     1     /* 0x1 */\r
180 #define SSH2_OPEN_CONNECT_FAILED                  2     /* 0x2 */\r
181 #define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE            3     /* 0x3 */\r
182 #define SSH2_OPEN_RESOURCE_SHORTAGE               4     /* 0x4 */\r
184 #define SSH2_EXTENDED_DATA_STDERR                 1     /* 0x1 */\r
186 /*\r
187  * Various remote-bug flags.\r
188  */\r
189 #define BUG_CHOKES_ON_SSH1_IGNORE                 1\r
190 #define BUG_SSH2_HMAC                             2\r
191 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD             4\r
192 #define BUG_CHOKES_ON_RSA                         8\r
193 #define BUG_SSH2_RSA_PADDING                     16\r
194 #define BUG_SSH2_DERIVEKEY                       32\r
195 #define BUG_SSH2_REKEY                           64\r
196 #define BUG_SSH2_PK_SESSIONID                   128\r
197 #define BUG_SSH2_MAXPKT                         256\r
198 #define BUG_CHOKES_ON_SSH2_IGNORE               512\r
199 #define BUG_CHOKES_ON_WINADJ                   1024\r
201 /*\r
202  * Codes for terminal modes.\r
203  * Most of these are the same in SSH-1 and SSH-2.\r
204  * This list is derived from RFC 4254 and\r
205  * SSH-1 RFC-1.2.31.\r
206  */\r
207 static const struct {\r
208     const char* const mode;\r
209     int opcode;\r
210     enum { TTY_OP_CHAR, TTY_OP_BOOL } type;\r
211 } ssh_ttymodes[] = {\r
212     /* "V" prefix discarded for special characters relative to SSH specs */\r
213     { "INTR",         1, TTY_OP_CHAR },\r
214     { "QUIT",         2, TTY_OP_CHAR },\r
215     { "ERASE",        3, TTY_OP_CHAR },\r
216     { "KILL",         4, TTY_OP_CHAR },\r
217     { "EOF",          5, TTY_OP_CHAR },\r
218     { "EOL",          6, TTY_OP_CHAR },\r
219     { "EOL2",         7, TTY_OP_CHAR },\r
220     { "START",        8, TTY_OP_CHAR },\r
221     { "STOP",         9, TTY_OP_CHAR },\r
222     { "SUSP",        10, TTY_OP_CHAR },\r
223     { "DSUSP",       11, TTY_OP_CHAR },\r
224     { "REPRINT",     12, TTY_OP_CHAR },\r
225     { "WERASE",      13, TTY_OP_CHAR },\r
226     { "LNEXT",       14, TTY_OP_CHAR },\r
227     { "FLUSH",       15, TTY_OP_CHAR },\r
228     { "SWTCH",       16, TTY_OP_CHAR },\r
229     { "STATUS",      17, TTY_OP_CHAR },\r
230     { "DISCARD",     18, TTY_OP_CHAR },\r
231     { "IGNPAR",      30, TTY_OP_BOOL },\r
232     { "PARMRK",      31, TTY_OP_BOOL },\r
233     { "INPCK",       32, TTY_OP_BOOL },\r
234     { "ISTRIP",      33, TTY_OP_BOOL },\r
235     { "INLCR",       34, TTY_OP_BOOL },\r
236     { "IGNCR",       35, TTY_OP_BOOL },\r
237     { "ICRNL",       36, TTY_OP_BOOL },\r
238     { "IUCLC",       37, TTY_OP_BOOL },\r
239     { "IXON",        38, TTY_OP_BOOL },\r
240     { "IXANY",       39, TTY_OP_BOOL },\r
241     { "IXOFF",       40, TTY_OP_BOOL },\r
242     { "IMAXBEL",     41, TTY_OP_BOOL },\r
243     { "ISIG",        50, TTY_OP_BOOL },\r
244     { "ICANON",      51, TTY_OP_BOOL },\r
245     { "XCASE",       52, TTY_OP_BOOL },\r
246     { "ECHO",        53, TTY_OP_BOOL },\r
247     { "ECHOE",       54, TTY_OP_BOOL },\r
248     { "ECHOK",       55, TTY_OP_BOOL },\r
249     { "ECHONL",      56, TTY_OP_BOOL },\r
250     { "NOFLSH",      57, TTY_OP_BOOL },\r
251     { "TOSTOP",      58, TTY_OP_BOOL },\r
252     { "IEXTEN",      59, TTY_OP_BOOL },\r
253     { "ECHOCTL",     60, TTY_OP_BOOL },\r
254     { "ECHOKE",      61, TTY_OP_BOOL },\r
255     { "PENDIN",      62, TTY_OP_BOOL }, /* XXX is this a real mode? */\r
256     { "OPOST",       70, TTY_OP_BOOL },\r
257     { "OLCUC",       71, TTY_OP_BOOL },\r
258     { "ONLCR",       72, TTY_OP_BOOL },\r
259     { "OCRNL",       73, TTY_OP_BOOL },\r
260     { "ONOCR",       74, TTY_OP_BOOL },\r
261     { "ONLRET",      75, TTY_OP_BOOL },\r
262     { "CS7",         90, TTY_OP_BOOL },\r
263     { "CS8",         91, TTY_OP_BOOL },\r
264     { "PARENB",      92, TTY_OP_BOOL },\r
265     { "PARODD",      93, TTY_OP_BOOL }\r
266 };\r
268 /* Miscellaneous other tty-related constants. */\r
269 #define SSH_TTY_OP_END            0\r
270 /* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */\r
271 #define SSH1_TTY_OP_ISPEED      192\r
272 #define SSH1_TTY_OP_OSPEED      193\r
273 #define SSH2_TTY_OP_ISPEED      128\r
274 #define SSH2_TTY_OP_OSPEED      129\r
276 /* Helper functions for parsing tty-related config. */\r
277 static unsigned int ssh_tty_parse_specchar(char *s)\r
279     unsigned int ret;\r
280     if (*s) {\r
281         char *next = NULL;\r
282         ret = ctrlparse(s, &next);\r
283         if (!next) ret = s[0];\r
284     } else {\r
285         ret = 255; /* special value meaning "don't set" */\r
286     }\r
287     return ret;\r
289 static unsigned int ssh_tty_parse_boolean(char *s)\r
291     if (stricmp(s, "yes") == 0 ||\r
292         stricmp(s, "on") == 0 ||\r
293         stricmp(s, "true") == 0 ||\r
294         stricmp(s, "+") == 0)\r
295         return 1; /* true */\r
296     else if (stricmp(s, "no") == 0 ||\r
297              stricmp(s, "off") == 0 ||\r
298              stricmp(s, "false") == 0 ||\r
299              stricmp(s, "-") == 0)\r
300         return 0; /* false */\r
301     else\r
302         return (atoi(s) != 0);\r
305 #define translate(x) if (type == x) return #x\r
306 #define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x\r
307 #define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x\r
308 static char *ssh1_pkt_type(int type)\r
310     translate(SSH1_MSG_DISCONNECT);\r
311     translate(SSH1_SMSG_PUBLIC_KEY);\r
312     translate(SSH1_CMSG_SESSION_KEY);\r
313     translate(SSH1_CMSG_USER);\r
314     translate(SSH1_CMSG_AUTH_RSA);\r
315     translate(SSH1_SMSG_AUTH_RSA_CHALLENGE);\r
316     translate(SSH1_CMSG_AUTH_RSA_RESPONSE);\r
317     translate(SSH1_CMSG_AUTH_PASSWORD);\r
318     translate(SSH1_CMSG_REQUEST_PTY);\r
319     translate(SSH1_CMSG_WINDOW_SIZE);\r
320     translate(SSH1_CMSG_EXEC_SHELL);\r
321     translate(SSH1_CMSG_EXEC_CMD);\r
322     translate(SSH1_SMSG_SUCCESS);\r
323     translate(SSH1_SMSG_FAILURE);\r
324     translate(SSH1_CMSG_STDIN_DATA);\r
325     translate(SSH1_SMSG_STDOUT_DATA);\r
326     translate(SSH1_SMSG_STDERR_DATA);\r
327     translate(SSH1_CMSG_EOF);\r
328     translate(SSH1_SMSG_EXIT_STATUS);\r
329     translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);\r
330     translate(SSH1_MSG_CHANNEL_OPEN_FAILURE);\r
331     translate(SSH1_MSG_CHANNEL_DATA);\r
332     translate(SSH1_MSG_CHANNEL_CLOSE);\r
333     translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);\r
334     translate(SSH1_SMSG_X11_OPEN);\r
335     translate(SSH1_CMSG_PORT_FORWARD_REQUEST);\r
336     translate(SSH1_MSG_PORT_OPEN);\r
337     translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING);\r
338     translate(SSH1_SMSG_AGENT_OPEN);\r
339     translate(SSH1_MSG_IGNORE);\r
340     translate(SSH1_CMSG_EXIT_CONFIRMATION);\r
341     translate(SSH1_CMSG_X11_REQUEST_FORWARDING);\r
342     translate(SSH1_CMSG_AUTH_RHOSTS_RSA);\r
343     translate(SSH1_MSG_DEBUG);\r
344     translate(SSH1_CMSG_REQUEST_COMPRESSION);\r
345     translate(SSH1_CMSG_AUTH_TIS);\r
346     translate(SSH1_SMSG_AUTH_TIS_CHALLENGE);\r
347     translate(SSH1_CMSG_AUTH_TIS_RESPONSE);\r
348     translate(SSH1_CMSG_AUTH_CCARD);\r
349     translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE);\r
350     translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);\r
351     return "unknown";\r
353 static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)\r
355     translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);\r
356     translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);\r
357     translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI);\r
358     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI);\r
359     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI);\r
360     translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);\r
361     translate(SSH2_MSG_DISCONNECT);\r
362     translate(SSH2_MSG_IGNORE);\r
363     translate(SSH2_MSG_UNIMPLEMENTED);\r
364     translate(SSH2_MSG_DEBUG);\r
365     translate(SSH2_MSG_SERVICE_REQUEST);\r
366     translate(SSH2_MSG_SERVICE_ACCEPT);\r
367     translate(SSH2_MSG_KEXINIT);\r
368     translate(SSH2_MSG_NEWKEYS);\r
369     translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);\r
370     translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);\r
371     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);\r
372     translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);\r
373     translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);\r
374     translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);\r
375     translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);\r
376     translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);\r
377     translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);\r
378     translate(SSH2_MSG_USERAUTH_REQUEST);\r
379     translate(SSH2_MSG_USERAUTH_FAILURE);\r
380     translate(SSH2_MSG_USERAUTH_SUCCESS);\r
381     translate(SSH2_MSG_USERAUTH_BANNER);\r
382     translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);\r
383     translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);\r
384     translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);\r
385     translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);\r
386     translate(SSH2_MSG_GLOBAL_REQUEST);\r
387     translate(SSH2_MSG_REQUEST_SUCCESS);\r
388     translate(SSH2_MSG_REQUEST_FAILURE);\r
389     translate(SSH2_MSG_CHANNEL_OPEN);\r
390     translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
391     translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
392     translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
393     translate(SSH2_MSG_CHANNEL_DATA);\r
394     translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);\r
395     translate(SSH2_MSG_CHANNEL_EOF);\r
396     translate(SSH2_MSG_CHANNEL_CLOSE);\r
397     translate(SSH2_MSG_CHANNEL_REQUEST);\r
398     translate(SSH2_MSG_CHANNEL_SUCCESS);\r
399     translate(SSH2_MSG_CHANNEL_FAILURE);\r
400     return "unknown";\r
402 #undef translate\r
403 #undef translatec\r
405 /* Enumeration values for fields in SSH-1 packets */\r
406 enum {\r
407     PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,\r
408     /* These values are for communicating relevant semantics of\r
409      * fields to the packet logging code. */\r
410     PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA\r
411 };\r
413 /*\r
414  * Coroutine mechanics for the sillier bits of the code. If these\r
415  * macros look impenetrable to you, you might find it helpful to\r
416  * read\r
417  * \r
418  *   http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\r
419  * \r
420  * which explains the theory behind these macros.\r
421  * \r
422  * In particular, if you are getting `case expression not constant'\r
423  * errors when building with MS Visual Studio, this is because MS's\r
424  * Edit and Continue debugging feature causes their compiler to\r
425  * violate ANSI C. To disable Edit and Continue debugging:\r
426  * \r
427  *  - right-click ssh.c in the FileView\r
428  *  - click Settings\r
429  *  - select the C/C++ tab and the General category\r
430  *  - under `Debug info:', select anything _other_ than `Program\r
431  *    Database for Edit and Continue'.\r
432  */\r
433 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;\r
434 #define crBeginState    crBegin(s->crLine)\r
435 #define crStateP(t, v)                          \\r
436     struct t *s;                                \\r
437     if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; }      \\r
438     s = (v);\r
439 #define crState(t)      crStateP(t, ssh->t)\r
440 #define crFinish(z)     } *crLine = 0; return (z); }\r
441 #define crFinishV       } *crLine = 0; return; }\r
442 #define crFinishFree(z) } sfree(s); return (z); }\r
443 #define crFinishFreeV   } sfree(s); return; }\r
444 #define crReturn(z)     \\r
445         do {\\r
446             *crLine =__LINE__; return (z); case __LINE__:;\\r
447         } while (0)\r
448 #define crReturnV       \\r
449         do {\\r
450             *crLine=__LINE__; return; case __LINE__:;\\r
451         } while (0)\r
452 #define crStop(z)       do{ *crLine = 0; return (z); }while(0)\r
453 #define crStopV         do{ *crLine = 0; return; }while(0)\r
454 #define crWaitUntil(c)  do { crReturn(0); } while (!(c))\r
455 #define crWaitUntilV(c) do { crReturnV; } while (!(c))\r
457 typedef struct ssh_tag *Ssh;\r
458 struct Packet;\r
460 static struct Packet *ssh1_pkt_init(int pkt_type);\r
461 static struct Packet *ssh2_pkt_init(int pkt_type);\r
462 static void ssh_pkt_ensure(struct Packet *, int length);\r
463 static void ssh_pkt_adddata(struct Packet *, const void *data, int len);\r
464 static void ssh_pkt_addbyte(struct Packet *, unsigned char value);\r
465 static void ssh2_pkt_addbool(struct Packet *, unsigned char value);\r
466 static void ssh_pkt_adduint32(struct Packet *, unsigned long value);\r
467 static void ssh_pkt_addstring_start(struct Packet *);\r
468 static void ssh_pkt_addstring_str(struct Packet *, const char *data);\r
469 static void ssh_pkt_addstring_data(struct Packet *, const char *data, int len);\r
470 static void ssh_pkt_addstring(struct Packet *, const char *data);\r
471 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);\r
472 static void ssh1_pkt_addmp(struct Packet *, Bignum b);\r
473 static void ssh2_pkt_addmp(struct Packet *, Bignum b);\r
474 static int ssh2_pkt_construct(Ssh, struct Packet *);\r
475 static void ssh2_pkt_send(Ssh, struct Packet *);\r
476 static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);\r
477 static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,\r
478                          struct Packet *pktin);\r
479 static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,\r
480                              struct Packet *pktin);\r
481 static void ssh2_channel_check_close(struct ssh_channel *c);\r
482 static void ssh_channel_destroy(struct ssh_channel *c);\r
484 /*\r
485  * Buffer management constants. There are several of these for\r
486  * various different purposes:\r
487  * \r
488  *  - SSH1_BUFFER_LIMIT is the amount of backlog that must build up\r
489  *    on a local data stream before we throttle the whole SSH\r
490  *    connection (in SSH-1 only). Throttling the whole connection is\r
491  *    pretty drastic so we set this high in the hope it won't\r
492  *    happen very often.\r
493  * \r
494  *  - SSH_MAX_BACKLOG is the amount of backlog that must build up\r
495  *    on the SSH connection itself before we defensively throttle\r
496  *    _all_ local data streams. This is pretty drastic too (though\r
497  *    thankfully unlikely in SSH-2 since the window mechanism should\r
498  *    ensure that the server never has any need to throttle its end\r
499  *    of the connection), so we set this high as well.\r
500  * \r
501  *  - OUR_V2_WINSIZE is the maximum window size we present on SSH-2\r
502  *    channels.\r
503  *\r
504  *  - OUR_V2_BIGWIN is the window size we advertise for the only\r
505  *    channel in a simple connection.  It must be <= INT_MAX.\r
506  *\r
507  *  - OUR_V2_MAXPKT is the official "maximum packet size" we send\r
508  *    to the remote side. This actually has nothing to do with the\r
509  *    size of the _packet_, but is instead a limit on the amount\r
510  *    of data we're willing to receive in a single SSH2 channel\r
511  *    data message.\r
512  *\r
513  *  - OUR_V2_PACKETLIMIT is actually the maximum size of SSH\r
514  *    _packet_ we're prepared to cope with.  It must be a multiple\r
515  *    of the cipher block size, and must be at least 35000.\r
516  */\r
518 #define SSH1_BUFFER_LIMIT 32768\r
519 #define SSH_MAX_BACKLOG 32768\r
520 #define OUR_V2_WINSIZE 16384\r
521 #define OUR_V2_BIGWIN 0x7fffffff\r
522 #define OUR_V2_MAXPKT 0x4000UL\r
523 #define OUR_V2_PACKETLIMIT 0x9000UL\r
525 const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };\r
527 const static struct ssh_mac *macs[] = {\r
528     &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5\r
529 };\r
530 const static struct ssh_mac *buggymacs[] = {\r
531     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5\r
532 };\r
534 static void *ssh_comp_none_init(void)\r
536     return NULL;\r
538 static void ssh_comp_none_cleanup(void *handle)\r
541 static int ssh_comp_none_block(void *handle, unsigned char *block, int len,\r
542                                unsigned char **outblock, int *outlen)\r
544     return 0;\r
546 static int ssh_comp_none_disable(void *handle)\r
548     return 0;\r
550 const static struct ssh_compress ssh_comp_none = {\r
551     "none", NULL,\r
552     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
553     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
554     ssh_comp_none_disable, NULL\r
555 };\r
556 extern const struct ssh_compress ssh_zlib;\r
557 const static struct ssh_compress *compressions[] = {\r
558     &ssh_zlib, &ssh_comp_none\r
559 };\r
561 enum {                                 /* channel types */\r
562     CHAN_MAINSESSION,\r
563     CHAN_X11,\r
564     CHAN_AGENT,\r
565     CHAN_SOCKDATA,\r
566     CHAN_SOCKDATA_DORMANT,             /* one the remote hasn't confirmed */\r
567     /*\r
568      * CHAN_ZOMBIE is used to indicate a channel for which we've\r
569      * already destroyed the local data source: for instance, if a\r
570      * forwarded port experiences a socket error on the local side, we\r
571      * immediately destroy its local socket and turn the SSH channel\r
572      * into CHAN_ZOMBIE.\r
573      */\r
574     CHAN_ZOMBIE\r
575 };\r
577 typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);\r
578 typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);\r
579 typedef void (*cchandler_fn_t)(struct ssh_channel *, struct Packet *, void *);\r
581 /*\r
582  * Each channel has a queue of outstanding CHANNEL_REQUESTS and their\r
583  * handlers.\r
584  */\r
585 struct outstanding_channel_request {\r
586     cchandler_fn_t handler;\r
587     void *ctx;\r
588     struct outstanding_channel_request *next;\r
589 };\r
591 /*\r
592  * 2-3-4 tree storing channels.\r
593  */\r
594 struct ssh_channel {\r
595     Ssh ssh;                           /* pointer back to main context */\r
596     unsigned remoteid, localid;\r
597     int type;\r
598     /* True if we opened this channel but server hasn't confirmed. */\r
599     int halfopen;\r
600     /*\r
601      * In SSH-1, this value contains four bits:\r
602      * \r
603      *   1   We have sent SSH1_MSG_CHANNEL_CLOSE.\r
604      *   2   We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
605      *   4   We have received SSH1_MSG_CHANNEL_CLOSE.\r
606      *   8   We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
607      * \r
608      * A channel is completely finished with when all four bits are set.\r
609      *\r
610      * In SSH-2, the four bits mean:\r
611      *\r
612      *   1   We have sent SSH2_MSG_CHANNEL_EOF.\r
613      *   2   We have sent SSH2_MSG_CHANNEL_CLOSE.\r
614      *   4   We have received SSH2_MSG_CHANNEL_EOF.\r
615      *   8   We have received SSH2_MSG_CHANNEL_CLOSE.\r
616      *\r
617      * A channel is completely finished with when we have both sent\r
618      * and received CLOSE.\r
619      *\r
620      * The symbolic constants below use the SSH-2 terminology, which\r
621      * is a bit confusing in SSH-1, but we have to use _something_.\r
622      */\r
623 #define CLOSES_SENT_EOF    1\r
624 #define CLOSES_SENT_CLOSE  2\r
625 #define CLOSES_RCVD_EOF    4\r
626 #define CLOSES_RCVD_CLOSE  8\r
627     int closes;\r
629     /*\r
630      * This flag indicates that an EOF is pending on the outgoing side\r
631      * of the channel: that is, wherever we're getting the data for\r
632      * this channel has sent us some data followed by EOF. We can't\r
633      * actually send the EOF until we've finished sending the data, so\r
634      * we set this flag instead to remind us to do so once our buffer\r
635      * is clear.\r
636      */\r
637     int pending_eof;\r
639     /*\r
640      * True if this channel is causing the underlying connection to be\r
641      * throttled.\r
642      */\r
643     int throttling_conn;\r
644     union {\r
645         struct ssh2_data_channel {\r
646             bufchain outbuffer;\r
647             unsigned remwindow, remmaxpkt;\r
648             /* locwindow is signed so we can cope with excess data. */\r
649             int locwindow, locmaxwin;\r
650             /*\r
651              * remlocwin is the amount of local window that we think\r
652              * the remote end had available to it after it sent the\r
653              * last data packet or window adjust ack.\r
654              */\r
655             int remlocwin;\r
656             /*\r
657              * These store the list of channel requests that haven't\r
658              * been acked.\r
659              */\r
660             struct outstanding_channel_request *chanreq_head, *chanreq_tail;\r
661             enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state;\r
662         } v2;\r
663     } v;\r
664     union {\r
665         struct ssh_agent_channel {\r
666             unsigned char *message;\r
667             unsigned char msglen[4];\r
668             unsigned lensofar, totallen;\r
669             int outstanding_requests;\r
670         } a;\r
671         struct ssh_x11_channel {\r
672             Socket s;\r
673         } x11;\r
674         struct ssh_pfd_channel {\r
675             Socket s;\r
676         } pfd;\r
677     } u;\r
678 };\r
680 /*\r
681  * 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2\r
682  * use this structure in different ways, reflecting SSH-2's\r
683  * altogether saner approach to port forwarding.\r
684  * \r
685  * In SSH-1, you arrange a remote forwarding by sending the server\r
686  * the remote port number, and the local destination host:port.\r
687  * When a connection comes in, the server sends you back that\r
688  * host:port pair, and you connect to it. This is a ready-made\r
689  * security hole if you're not on the ball: a malicious server\r
690  * could send you back _any_ host:port pair, so if you trustingly\r
691  * connect to the address it gives you then you've just opened the\r
692  * entire inside of your corporate network just by connecting\r
693  * through it to a dodgy SSH server. Hence, we must store a list of\r
694  * host:port pairs we _are_ trying to forward to, and reject a\r
695  * connection request from the server if it's not in the list.\r
696  * \r
697  * In SSH-2, each side of the connection minds its own business and\r
698  * doesn't send unnecessary information to the other. You arrange a\r
699  * remote forwarding by sending the server just the remote port\r
700  * number. When a connection comes in, the server tells you which\r
701  * of its ports was connected to; and _you_ have to remember what\r
702  * local host:port pair went with that port number.\r
703  * \r
704  * Hence, in SSH-1 this structure is indexed by destination\r
705  * host:port pair, whereas in SSH-2 it is indexed by source port.\r
706  */\r
707 struct ssh_portfwd; /* forward declaration */\r
709 struct ssh_rportfwd {\r
710     unsigned sport, dport;\r
711     char dhost[256];\r
712     char *sportdesc;\r
713     struct ssh_portfwd *pfrec;\r
714 };\r
715 #define free_rportfwd(pf) ( \\r
716     ((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) )\r
718 /*\r
719  * Separately to the rportfwd tree (which is for looking up port\r
720  * open requests from the server), a tree of _these_ structures is\r
721  * used to keep track of all the currently open port forwardings,\r
722  * so that we can reconfigure in mid-session if the user requests\r
723  * it.\r
724  */\r
725 struct ssh_portfwd {\r
726     enum { DESTROY, KEEP, CREATE } status;\r
727     int type;\r
728     unsigned sport, dport;\r
729     char *saddr, *daddr;\r
730     char *sserv, *dserv;\r
731     struct ssh_rportfwd *remote;\r
732     int addressfamily;\r
733     void *local;\r
734 };\r
735 #define free_portfwd(pf) ( \\r
736     ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \\r
737              sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )\r
739 struct Packet {\r
740     long length;            /* length of `data' actually used */\r
741     long forcepad;          /* SSH-2: force padding to at least this length */\r
742     int type;               /* only used for incoming packets */\r
743     unsigned long sequence; /* SSH-2 incoming sequence number */\r
744     unsigned char *data;    /* allocated storage */\r
745     unsigned char *body;    /* offset of payload within `data' */\r
746     long savedpos;          /* temporary index into `data' (for strings) */\r
747     long maxlen;            /* amount of storage allocated for `data' */\r
748     long encrypted_len;     /* for SSH-2 total-size counting */\r
750     /*\r
751      * State associated with packet logging\r
752      */\r
753     int logmode;\r
754     int nblanks;\r
755     struct logblank_t *blanks;\r
756 };\r
758 static void ssh1_protocol(Ssh ssh, void *vin, int inlen,\r
759                           struct Packet *pktin);\r
760 static void ssh2_protocol(Ssh ssh, void *vin, int inlen,\r
761                           struct Packet *pktin);\r
762 static void ssh1_protocol_setup(Ssh ssh);\r
763 static void ssh2_protocol_setup(Ssh ssh);\r
764 static void ssh_size(void *handle, int width, int height);\r
765 static void ssh_special(void *handle, Telnet_Special);\r
766 static int ssh2_try_send(struct ssh_channel *c);\r
767 static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len);\r
768 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);\r
769 static void ssh2_set_window(struct ssh_channel *c, int newwin);\r
770 static int ssh_sendbuffer(void *handle);\r
771 static int ssh_do_close(Ssh ssh, int notify_exit);\r
772 static unsigned long ssh_pkt_getuint32(struct Packet *pkt);\r
773 static int ssh2_pkt_getbool(struct Packet *pkt);\r
774 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);\r
775 static void ssh2_timer(void *ctx, unsigned long now);\r
776 static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,\r
777                               struct Packet *pktin);\r
778 static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin);\r
780 struct rdpkt1_state_tag {\r
781     long len, pad, biglen, to_read;\r
782     unsigned long realcrc, gotcrc;\r
783     unsigned char *p;\r
784     int i;\r
785     int chunk;\r
786     struct Packet *pktin;\r
787 };\r
789 struct rdpkt2_state_tag {\r
790     long len, pad, payload, packetlen, maclen;\r
791     int i;\r
792     int cipherblk;\r
793     unsigned long incoming_sequence;\r
794     struct Packet *pktin;\r
795 };\r
797 struct queued_handler;\r
798 struct queued_handler {\r
799     int msg1, msg2;\r
800     chandler_fn_t handler;\r
801     void *ctx;\r
802     struct queued_handler *next;\r
803 };\r
805 struct ssh_tag {\r
806     const struct plug_function_table *fn;\r
807     /* the above field _must_ be first in the structure */\r
809     char *v_c, *v_s;\r
810     void *exhash;\r
812     Socket s;\r
814     void *ldisc;\r
815     void *logctx;\r
817     unsigned char session_key[32];\r
818     int v1_compressing;\r
819     int v1_remote_protoflags;\r
820     int v1_local_protoflags;\r
821     int agentfwd_enabled;\r
822     int X11_fwd_enabled;\r
823     int remote_bugs;\r
824     const struct ssh_cipher *cipher;\r
825     void *v1_cipher_ctx;\r
826     void *crcda_ctx;\r
827     const struct ssh2_cipher *cscipher, *sccipher;\r
828     void *cs_cipher_ctx, *sc_cipher_ctx;\r
829     const struct ssh_mac *csmac, *scmac;\r
830     void *cs_mac_ctx, *sc_mac_ctx;\r
831     const struct ssh_compress *cscomp, *sccomp;\r
832     void *cs_comp_ctx, *sc_comp_ctx;\r
833     const struct ssh_kex *kex;\r
834     const struct ssh_signkey *hostkey;\r
835     unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN];\r
836     int v2_session_id_len;\r
837     void *kex_ctx;\r
839     char *savedhost;\r
840     int savedport;\r
841     int send_ok;\r
842     int echoing, editing;\r
844     void *frontend;\r
846     int ospeed, ispeed;                /* temporaries */\r
847     int term_width, term_height;\r
849     tree234 *channels;                 /* indexed by local id */\r
850     struct ssh_channel *mainchan;      /* primary session channel */\r
851     int ncmode;                        /* is primary channel direct-tcpip? */\r
852     int exitcode;\r
853     int close_expected;\r
854     int clean_exit;\r
856     tree234 *rportfwds, *portfwds;\r
858     enum {\r
859         SSH_STATE_PREPACKET,\r
860         SSH_STATE_BEFORE_SIZE,\r
861         SSH_STATE_INTERMED,\r
862         SSH_STATE_SESSION,\r
863         SSH_STATE_CLOSED\r
864     } state;\r
866     int size_needed, eof_needed;\r
867     int sent_console_eof;\r
868     int got_pty;           /* affects EOF behaviour on main channel */\r
870     struct Packet **queue;\r
871     int queuelen, queuesize;\r
872     int queueing;\r
873     unsigned char *deferred_send_data;\r
874     int deferred_len, deferred_size;\r
876     /*\r
877      * Gross hack: pscp will try to start SFTP but fall back to\r
878      * scp1 if that fails. This variable is the means by which\r
879      * scp.c can reach into the SSH code and find out which one it\r
880      * got.\r
881      */\r
882     int fallback_cmd;\r
884     bufchain banner;    /* accumulates banners during do_ssh2_authconn */\r
886     Pkt_KCtx pkt_kctx;\r
887     Pkt_ACtx pkt_actx;\r
889     struct X11Display *x11disp;\r
891     int version;\r
892     int conn_throttle_count;\r
893     int overall_bufsize;\r
894     int throttled_all;\r
895     int v1_stdout_throttling;\r
896     unsigned long v2_outgoing_sequence;\r
898     int ssh1_rdpkt_crstate;\r
899     int ssh2_rdpkt_crstate;\r
900     int ssh_gotdata_crstate;\r
901     int do_ssh1_connection_crstate;\r
903     void *do_ssh_init_state;\r
904     void *do_ssh1_login_state;\r
905     void *do_ssh2_transport_state;\r
906     void *do_ssh2_authconn_state;\r
908     struct rdpkt1_state_tag rdpkt1_state;\r
909     struct rdpkt2_state_tag rdpkt2_state;\r
911     /* SSH-1 and SSH-2 use this for different things, but both use it */\r
912     int protocol_initial_phase_done;\r
914     void (*protocol) (Ssh ssh, void *vin, int inlen,\r
915                       struct Packet *pkt);\r
916     struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen);\r
918     /*\r
919      * We maintain our own copy of a Conf structure here. That way,\r
920      * when we're passed a new one for reconfiguration, we can check\r
921      * the differences and potentially reconfigure port forwardings\r
922      * etc in mid-session.\r
923      */\r
924     Conf *conf;\r
926     /*\r
927      * Values cached out of conf so as to avoid the tree234 lookup\r
928      * cost every time they're used.\r
929      */\r
930     int logomitdata;\r
932     /*\r
933      * Dynamically allocated username string created during SSH\r
934      * login. Stored in here rather than in the coroutine state so\r
935      * that it'll be reliably freed if we shut down the SSH session\r
936      * at some unexpected moment.\r
937      */\r
938     char *username;\r
940     /*\r
941      * Used to transfer data back from async callbacks.\r
942      */\r
943     void *agent_response;\r
944     int agent_response_len;\r
945     int user_response;\r
947     /*\r
948      * The SSH connection can be set as `frozen', meaning we are\r
949      * not currently accepting incoming data from the network. This\r
950      * is slightly more serious than setting the _socket_ as\r
951      * frozen, because we may already have had data passed to us\r
952      * from the network which we need to delay processing until\r
953      * after the freeze is lifted, so we also need a bufchain to\r
954      * store that data.\r
955      */\r
956     int frozen;\r
957     bufchain queued_incoming_data;\r
959     /*\r
960      * Dispatch table for packet types that we may have to deal\r
961      * with at any time.\r
962      */\r
963     handler_fn_t packet_dispatch[256];\r
965     /*\r
966      * Queues of one-off handler functions for success/failure\r
967      * indications from a request.\r
968      */\r
969     struct queued_handler *qhead, *qtail;\r
970     handler_fn_t q_saved_handler1, q_saved_handler2;\r
972     /*\r
973      * This module deals with sending keepalives.\r
974      */\r
975     Pinger pinger;\r
977     /*\r
978      * Track incoming and outgoing data sizes and time, for\r
979      * size-based rekeys.\r
980      */\r
981     unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;\r
982     unsigned long max_data_size;\r
983     int kex_in_progress;\r
984     unsigned long next_rekey, last_rekey;\r
985     char *deferred_rekey_reason;    /* points to STATIC string; don't free */\r
987     /*\r
988      * Fully qualified host name, which we need if doing GSSAPI.\r
989      */\r
990     char *fullhostname;\r
992 #ifndef NO_GSSAPI\r
993     /*\r
994      * GSSAPI libraries for this session.\r
995      */\r
996     struct ssh_gss_liblist *gsslibs;\r
997 #endif\r
998 };\r
1000 #define logevent(s) logevent(ssh->frontend, s)\r
1002 /* logevent, only printf-formatted. */\r
1003 static void logeventf(Ssh ssh, const char *fmt, ...)\r
1005     va_list ap;\r
1006     char *buf;\r
1008     va_start(ap, fmt);\r
1009     buf = dupvprintf(fmt, ap);\r
1010     va_end(ap);\r
1011     logevent(buf);\r
1012     sfree(buf);\r
1015 static void bomb_out(Ssh ssh, char *text)\r
1017     ssh_do_close(ssh, FALSE);\r
1018     logevent(text);\r
1019     connection_fatal(ssh->frontend, "%s", text);\r
1020     sfree(text);\r
1023 #define bombout(msg) bomb_out(ssh, dupprintf msg)\r
1025 /* Functions to leave bits out of the SSH packet log file. */\r
1027 static void dont_log_password(Ssh ssh, struct Packet *pkt, int blanktype)\r
1029     if (conf_get_int(ssh->conf, CONF_logomitpass))\r
1030         pkt->logmode = blanktype;\r
1033 static void dont_log_data(Ssh ssh, struct Packet *pkt, int blanktype)\r
1035     if (ssh->logomitdata)\r
1036         pkt->logmode = blanktype;\r
1039 static void end_log_omission(Ssh ssh, struct Packet *pkt)\r
1041     pkt->logmode = PKTLOG_EMIT;\r
1044 /* Helper function for common bits of parsing ttymodes. */\r
1045 static void parse_ttymodes(Ssh ssh,\r
1046                            void (*do_mode)(void *data, char *mode, char *val),\r
1047                            void *data)\r
1049     char *key, *val;\r
1051     for (val = conf_get_str_strs(ssh->conf, CONF_ttymodes, NULL, &key);\r
1052          val != NULL;\r
1053          val = conf_get_str_strs(ssh->conf, CONF_ttymodes, key, &key)) {\r
1054         /*\r
1055          * val[0] is either 'V', indicating that an explicit value\r
1056          * follows it, or 'A' indicating that we should pass the\r
1057          * value through from the local environment via get_ttymode.\r
1058          */\r
1059         if (val[0] == 'A') {\r
1060             val = get_ttymode(ssh->frontend, key);\r
1061             if (val) {\r
1062                 do_mode(data, key, val);\r
1063                 sfree(val);\r
1064             }\r
1065         } else\r
1066             do_mode(data, key, val + 1);               /* skip the 'V' */\r
1067     }\r
1070 static int ssh_channelcmp(void *av, void *bv)\r
1072     struct ssh_channel *a = (struct ssh_channel *) av;\r
1073     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1074     if (a->localid < b->localid)\r
1075         return -1;\r
1076     if (a->localid > b->localid)\r
1077         return +1;\r
1078     return 0;\r
1080 static int ssh_channelfind(void *av, void *bv)\r
1082     unsigned *a = (unsigned *) av;\r
1083     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1084     if (*a < b->localid)\r
1085         return -1;\r
1086     if (*a > b->localid)\r
1087         return +1;\r
1088     return 0;\r
1091 static int ssh_rportcmp_ssh1(void *av, void *bv)\r
1093     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1094     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1095     int i;\r
1096     if ( (i = strcmp(a->dhost, b->dhost)) != 0)\r
1097         return i < 0 ? -1 : +1;\r
1098     if (a->dport > b->dport)\r
1099         return +1;\r
1100     if (a->dport < b->dport)\r
1101         return -1;\r
1102     return 0;\r
1105 static int ssh_rportcmp_ssh2(void *av, void *bv)\r
1107     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1108     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1110     if (a->sport > b->sport)\r
1111         return +1;\r
1112     if (a->sport < b->sport)\r
1113         return -1;\r
1114     return 0;\r
1117 /*\r
1118  * Special form of strcmp which can cope with NULL inputs. NULL is\r
1119  * defined to sort before even the empty string.\r
1120  */\r
1121 static int nullstrcmp(const char *a, const char *b)\r
1123     if (a == NULL && b == NULL)\r
1124         return 0;\r
1125     if (a == NULL)\r
1126         return -1;\r
1127     if (b == NULL)\r
1128         return +1;\r
1129     return strcmp(a, b);\r
1132 static int ssh_portcmp(void *av, void *bv)\r
1134     struct ssh_portfwd *a = (struct ssh_portfwd *) av;\r
1135     struct ssh_portfwd *b = (struct ssh_portfwd *) bv;\r
1136     int i;\r
1137     if (a->type > b->type)\r
1138         return +1;\r
1139     if (a->type < b->type)\r
1140         return -1;\r
1141     if (a->addressfamily > b->addressfamily)\r
1142         return +1;\r
1143     if (a->addressfamily < b->addressfamily)\r
1144         return -1;\r
1145     if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)\r
1146         return i < 0 ? -1 : +1;\r
1147     if (a->sport > b->sport)\r
1148         return +1;\r
1149     if (a->sport < b->sport)\r
1150         return -1;\r
1151     if (a->type != 'D') {\r
1152         if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)\r
1153             return i < 0 ? -1 : +1;\r
1154         if (a->dport > b->dport)\r
1155             return +1;\r
1156         if (a->dport < b->dport)\r
1157             return -1;\r
1158     }\r
1159     return 0;\r
1162 static int alloc_channel_id(Ssh ssh)\r
1164     const unsigned CHANNEL_NUMBER_OFFSET = 256;\r
1165     unsigned low, high, mid;\r
1166     int tsize;\r
1167     struct ssh_channel *c;\r
1169     /*\r
1170      * First-fit allocation of channel numbers: always pick the\r
1171      * lowest unused one. To do this, binary-search using the\r
1172      * counted B-tree to find the largest channel ID which is in a\r
1173      * contiguous sequence from the beginning. (Precisely\r
1174      * everything in that sequence must have ID equal to its tree\r
1175      * index plus CHANNEL_NUMBER_OFFSET.)\r
1176      */\r
1177     tsize = count234(ssh->channels);\r
1179     low = -1;\r
1180     high = tsize;\r
1181     while (high - low > 1) {\r
1182         mid = (high + low) / 2;\r
1183         c = index234(ssh->channels, mid);\r
1184         if (c->localid == mid + CHANNEL_NUMBER_OFFSET)\r
1185             low = mid;                 /* this one is fine */\r
1186         else\r
1187             high = mid;                /* this one is past it */\r
1188     }\r
1189     /*\r
1190      * Now low points to either -1, or the tree index of the\r
1191      * largest ID in the initial sequence.\r
1192      */\r
1193     {\r
1194         unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;\r
1195         assert(NULL == find234(ssh->channels, &i, ssh_channelfind));\r
1196     }\r
1197     return low + 1 + CHANNEL_NUMBER_OFFSET;\r
1200 static void c_write_stderr(int trusted, const char *buf, int len)\r
1202     int i;\r
1203     for (i = 0; i < len; i++)\r
1204         if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60)))\r
1205             fputc(buf[i], stderr);\r
1208 static void c_write(Ssh ssh, const char *buf, int len)\r
1210     if (flags & FLAG_STDERR)\r
1211         c_write_stderr(1, buf, len);\r
1212     else\r
1213         from_backend(ssh->frontend, 1, buf, len);\r
1216 static void c_write_untrusted(Ssh ssh, const char *buf, int len)\r
1218     if (flags & FLAG_STDERR)\r
1219         c_write_stderr(0, buf, len);\r
1220     else\r
1221         from_backend_untrusted(ssh->frontend, buf, len);\r
1224 static void c_write_str(Ssh ssh, const char *buf)\r
1226     c_write(ssh, buf, strlen(buf));\r
1229 static void ssh_free_packet(struct Packet *pkt)\r
1231     sfree(pkt->data);\r
1232     sfree(pkt);\r
1234 static struct Packet *ssh_new_packet(void)\r
1236     struct Packet *pkt = snew(struct Packet);\r
1238     pkt->body = pkt->data = NULL;\r
1239     pkt->maxlen = 0;\r
1240     pkt->logmode = PKTLOG_EMIT;\r
1241     pkt->nblanks = 0;\r
1242     pkt->blanks = NULL;\r
1244     return pkt;\r
1247 /*\r
1248  * Collect incoming data in the incoming packet buffer.\r
1249  * Decipher and verify the packet when it is completely read.\r
1250  * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.\r
1251  * Update the *data and *datalen variables.\r
1252  * Return a Packet structure when a packet is completed.\r
1253  */\r
1254 static struct Packet *ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)\r
1256     struct rdpkt1_state_tag *st = &ssh->rdpkt1_state;\r
1258     crBegin(ssh->ssh1_rdpkt_crstate);\r
1260     st->pktin = ssh_new_packet();\r
1262     st->pktin->type = 0;\r
1263     st->pktin->length = 0;\r
1265     for (st->i = st->len = 0; st->i < 4; st->i++) {\r
1266         while ((*datalen) == 0)\r
1267             crReturn(NULL);\r
1268         st->len = (st->len << 8) + **data;\r
1269         (*data)++, (*datalen)--;\r
1270     }\r
1272     st->pad = 8 - (st->len % 8);\r
1273     st->biglen = st->len + st->pad;\r
1274     st->pktin->length = st->len - 5;\r
1276     if (st->biglen < 0) {\r
1277         bombout(("Extremely large packet length from server suggests"\r
1278                  " data stream corruption"));\r
1279         ssh_free_packet(st->pktin);\r
1280         crStop(NULL);\r
1281     }\r
1283     st->pktin->maxlen = st->biglen;\r
1284     st->pktin->data = snewn(st->biglen + APIEXTRA, unsigned char);\r
1286     st->to_read = st->biglen;\r
1287     st->p = st->pktin->data;\r
1288     while (st->to_read > 0) {\r
1289         st->chunk = st->to_read;\r
1290         while ((*datalen) == 0)\r
1291             crReturn(NULL);\r
1292         if (st->chunk > (*datalen))\r
1293             st->chunk = (*datalen);\r
1294         memcpy(st->p, *data, st->chunk);\r
1295         *data += st->chunk;\r
1296         *datalen -= st->chunk;\r
1297         st->p += st->chunk;\r
1298         st->to_read -= st->chunk;\r
1299     }\r
1301     if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data,\r
1302                                      st->biglen, NULL)) {\r
1303         bombout(("Network attack (CRC compensation) detected!"));\r
1304         ssh_free_packet(st->pktin);\r
1305         crStop(NULL);\r
1306     }\r
1308     if (ssh->cipher)\r
1309         ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen);\r
1311     st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4);\r
1312     st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4);\r
1313     if (st->gotcrc != st->realcrc) {\r
1314         bombout(("Incorrect CRC received on packet"));\r
1315         ssh_free_packet(st->pktin);\r
1316         crStop(NULL);\r
1317     }\r
1319     st->pktin->body = st->pktin->data + st->pad + 1;\r
1320     st->pktin->savedpos = 0;\r
1322     if (ssh->v1_compressing) {\r
1323         unsigned char *decompblk;\r
1324         int decomplen;\r
1325         if (!zlib_decompress_block(ssh->sc_comp_ctx,\r
1326                                    st->pktin->body - 1, st->pktin->length + 1,\r
1327                                    &decompblk, &decomplen)) {\r
1328             bombout(("Zlib decompression encountered invalid data"));\r
1329             ssh_free_packet(st->pktin);\r
1330             crStop(NULL);\r
1331         }\r
1333         if (st->pktin->maxlen < st->pad + decomplen) {\r
1334             st->pktin->maxlen = st->pad + decomplen;\r
1335             st->pktin->data = sresize(st->pktin->data,\r
1336                                       st->pktin->maxlen + APIEXTRA,\r
1337                                       unsigned char);\r
1338             st->pktin->body = st->pktin->data + st->pad + 1;\r
1339         }\r
1341         memcpy(st->pktin->body - 1, decompblk, decomplen);\r
1342         sfree(decompblk);\r
1343         st->pktin->length = decomplen - 1;\r
1344     }\r
1346     st->pktin->type = st->pktin->body[-1];\r
1348     /*\r
1349      * Log incoming packet, possibly omitting sensitive fields.\r
1350      */\r
1351     if (ssh->logctx) {\r
1352         int nblanks = 0;\r
1353         struct logblank_t blank;\r
1354         if (ssh->logomitdata) {\r
1355             int do_blank = FALSE, blank_prefix = 0;\r
1356             /* "Session data" packets - omit the data field */\r
1357             if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) ||\r
1358                 (st->pktin->type == SSH1_SMSG_STDERR_DATA)) {\r
1359                 do_blank = TRUE; blank_prefix = 4;\r
1360             } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {\r
1361                 do_blank = TRUE; blank_prefix = 8;\r
1362             }\r
1363             if (do_blank) {\r
1364                 blank.offset = blank_prefix;\r
1365                 blank.len = st->pktin->length;\r
1366                 blank.type = PKTLOG_OMIT;\r
1367                 nblanks = 1;\r
1368             }\r
1369         }\r
1370         log_packet(ssh->logctx,\r
1371                    PKT_INCOMING, st->pktin->type,\r
1372                    ssh1_pkt_type(st->pktin->type),\r
1373                    st->pktin->body, st->pktin->length,\r
1374                    nblanks, &blank, NULL);\r
1375     }\r
1377     crFinish(st->pktin);\r
1380 static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)\r
1382     struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;\r
1384     crBegin(ssh->ssh2_rdpkt_crstate);\r
1386     st->pktin = ssh_new_packet();\r
1388     st->pktin->type = 0;\r
1389     st->pktin->length = 0;\r
1390     if (ssh->sccipher)\r
1391         st->cipherblk = ssh->sccipher->blksize;\r
1392     else\r
1393         st->cipherblk = 8;\r
1394     if (st->cipherblk < 8)\r
1395         st->cipherblk = 8;\r
1396     st->maclen = ssh->scmac ? ssh->scmac->len : 0;\r
1398     if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&\r
1399         ssh->scmac) {\r
1400         /*\r
1401          * When dealing with a CBC-mode cipher, we want to avoid the\r
1402          * possibility of an attacker's tweaking the ciphertext stream\r
1403          * so as to cause us to feed the same block to the block\r
1404          * cipher more than once and thus leak information\r
1405          * (VU#958563).  The way we do this is not to take any\r
1406          * decisions on the basis of anything we've decrypted until\r
1407          * we've verified it with a MAC.  That includes the packet\r
1408          * length, so we just read data and check the MAC repeatedly,\r
1409          * and when the MAC passes, see if the length we've got is\r
1410          * plausible.\r
1411          */\r
1413         /* May as well allocate the whole lot now. */\r
1414         st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,\r
1415                                 unsigned char);\r
1417         /* Read an amount corresponding to the MAC. */\r
1418         for (st->i = 0; st->i < st->maclen; st->i++) {\r
1419             while ((*datalen) == 0)\r
1420                 crReturn(NULL);\r
1421             st->pktin->data[st->i] = *(*data)++;\r
1422             (*datalen)--;\r
1423         }\r
1425         st->packetlen = 0;\r
1426         {\r
1427             unsigned char seq[4];\r
1428             ssh->scmac->start(ssh->sc_mac_ctx);\r
1429             PUT_32BIT(seq, st->incoming_sequence);\r
1430             ssh->scmac->bytes(ssh->sc_mac_ctx, seq, 4);\r
1431         }\r
1433         for (;;) { /* Once around this loop per cipher block. */\r
1434             /* Read another cipher-block's worth, and tack it onto the end. */\r
1435             for (st->i = 0; st->i < st->cipherblk; st->i++) {\r
1436                 while ((*datalen) == 0)\r
1437                     crReturn(NULL);\r
1438                 st->pktin->data[st->packetlen+st->maclen+st->i] = *(*data)++;\r
1439                 (*datalen)--;\r
1440             }\r
1441             /* Decrypt one more block (a little further back in the stream). */\r
1442             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1443                                    st->pktin->data + st->packetlen,\r
1444                                    st->cipherblk);\r
1445             /* Feed that block to the MAC. */\r
1446             ssh->scmac->bytes(ssh->sc_mac_ctx,\r
1447                               st->pktin->data + st->packetlen, st->cipherblk);\r
1448             st->packetlen += st->cipherblk;\r
1449             /* See if that gives us a valid packet. */\r
1450             if (ssh->scmac->verresult(ssh->sc_mac_ctx,\r
1451                                       st->pktin->data + st->packetlen) &&\r
1452                 ((st->len = toint(GET_32BIT(st->pktin->data))) ==\r
1453                  st->packetlen-4))\r
1454                     break;\r
1455             if (st->packetlen >= OUR_V2_PACKETLIMIT) {\r
1456                 bombout(("No valid incoming packet found"));\r
1457                 ssh_free_packet(st->pktin);\r
1458                 crStop(NULL);\r
1459             }       \r
1460         }\r
1461         st->pktin->maxlen = st->packetlen + st->maclen;\r
1462         st->pktin->data = sresize(st->pktin->data,\r
1463                                   st->pktin->maxlen + APIEXTRA,\r
1464                                   unsigned char);\r
1465     } else {\r
1466         st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);\r
1468         /*\r
1469          * Acquire and decrypt the first block of the packet. This will\r
1470          * contain the length and padding details.\r
1471          */\r
1472         for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {\r
1473             while ((*datalen) == 0)\r
1474                 crReturn(NULL);\r
1475             st->pktin->data[st->i] = *(*data)++;\r
1476             (*datalen)--;\r
1477         }\r
1479         if (ssh->sccipher)\r
1480             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1481                                    st->pktin->data, st->cipherblk);\r
1483         /*\r
1484          * Now get the length figure.\r
1485          */\r
1486         st->len = toint(GET_32BIT(st->pktin->data));\r
1488         /*\r
1489          * _Completely_ silly lengths should be stomped on before they\r
1490          * do us any more damage.\r
1491          */\r
1492         if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||\r
1493             (st->len + 4) % st->cipherblk != 0) {\r
1494             bombout(("Incoming packet was garbled on decryption"));\r
1495             ssh_free_packet(st->pktin);\r
1496             crStop(NULL);\r
1497         }\r
1499         /*\r
1500          * So now we can work out the total packet length.\r
1501          */\r
1502         st->packetlen = st->len + 4;\r
1504         /*\r
1505          * Allocate memory for the rest of the packet.\r
1506          */\r
1507         st->pktin->maxlen = st->packetlen + st->maclen;\r
1508         st->pktin->data = sresize(st->pktin->data,\r
1509                                   st->pktin->maxlen + APIEXTRA,\r
1510                                   unsigned char);\r
1512         /*\r
1513          * Read and decrypt the remainder of the packet.\r
1514          */\r
1515         for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;\r
1516              st->i++) {\r
1517             while ((*datalen) == 0)\r
1518                 crReturn(NULL);\r
1519             st->pktin->data[st->i] = *(*data)++;\r
1520             (*datalen)--;\r
1521         }\r
1522         /* Decrypt everything _except_ the MAC. */\r
1523         if (ssh->sccipher)\r
1524             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1525                                    st->pktin->data + st->cipherblk,\r
1526                                    st->packetlen - st->cipherblk);\r
1528         /*\r
1529          * Check the MAC.\r
1530          */\r
1531         if (ssh->scmac\r
1532             && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,\r
1533                                    st->len + 4, st->incoming_sequence)) {\r
1534             bombout(("Incorrect MAC received on packet"));\r
1535             ssh_free_packet(st->pktin);\r
1536             crStop(NULL);\r
1537         }\r
1538     }\r
1539     /* Get and sanity-check the amount of random padding. */\r
1540     st->pad = st->pktin->data[4];\r
1541     if (st->pad < 4 || st->len - st->pad < 1) {\r
1542         bombout(("Invalid padding length on received packet"));\r
1543         ssh_free_packet(st->pktin);\r
1544         crStop(NULL);\r
1545     }\r
1546     /*\r
1547      * This enables us to deduce the payload length.\r
1548      */\r
1549     st->payload = st->len - st->pad - 1;\r
1551     st->pktin->length = st->payload + 5;\r
1552     st->pktin->encrypted_len = st->packetlen;\r
1554     st->pktin->sequence = st->incoming_sequence++;\r
1556     /*\r
1557      * Decompress packet payload.\r
1558      */\r
1559     {\r
1560         unsigned char *newpayload;\r
1561         int newlen;\r
1562         if (ssh->sccomp &&\r
1563             ssh->sccomp->decompress(ssh->sc_comp_ctx,\r
1564                                     st->pktin->data + 5, st->pktin->length - 5,\r
1565                                     &newpayload, &newlen)) {\r
1566             if (st->pktin->maxlen < newlen + 5) {\r
1567                 st->pktin->maxlen = newlen + 5;\r
1568                 st->pktin->data = sresize(st->pktin->data,\r
1569                                           st->pktin->maxlen + APIEXTRA,\r
1570                                           unsigned char);\r
1571             }\r
1572             st->pktin->length = 5 + newlen;\r
1573             memcpy(st->pktin->data + 5, newpayload, newlen);\r
1574             sfree(newpayload);\r
1575         }\r
1576     }\r
1578     st->pktin->savedpos = 6;\r
1579     st->pktin->body = st->pktin->data;\r
1580     st->pktin->type = st->pktin->data[5];\r
1582     /*\r
1583      * Log incoming packet, possibly omitting sensitive fields.\r
1584      */\r
1585     if (ssh->logctx) {\r
1586         int nblanks = 0;\r
1587         struct logblank_t blank;\r
1588         if (ssh->logomitdata) {\r
1589             int do_blank = FALSE, blank_prefix = 0;\r
1590             /* "Session data" packets - omit the data field */\r
1591             if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) {\r
1592                 do_blank = TRUE; blank_prefix = 8;\r
1593             } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {\r
1594                 do_blank = TRUE; blank_prefix = 12;\r
1595             }\r
1596             if (do_blank) {\r
1597                 blank.offset = blank_prefix;\r
1598                 blank.len = (st->pktin->length-6) - blank_prefix;\r
1599                 blank.type = PKTLOG_OMIT;\r
1600                 nblanks = 1;\r
1601             }\r
1602         }\r
1603         log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type,\r
1604                    ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
1605                                  st->pktin->type),\r
1606                    st->pktin->data+6, st->pktin->length-6,\r
1607                    nblanks, &blank, &st->pktin->sequence);\r
1608     }\r
1610     crFinish(st->pktin);\r
1613 static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p)\r
1615     int pad, biglen, i, pktoffs;\r
1616     unsigned long crc;\r
1617 #ifdef __SC__\r
1618     /*\r
1619      * XXX various versions of SC (including 8.8.4) screw up the\r
1620      * register allocation in this function and use the same register\r
1621      * (D6) for len and as a temporary, with predictable results.  The\r
1622      * following sledgehammer prevents this.\r
1623      */\r
1624     volatile\r
1625 #endif\r
1626     int len;\r
1628     if (ssh->logctx)\r
1629         log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],\r
1630                    ssh1_pkt_type(pkt->data[12]),\r
1631                    pkt->body, pkt->length - (pkt->body - pkt->data),\r
1632                    pkt->nblanks, pkt->blanks, NULL);\r
1633     sfree(pkt->blanks); pkt->blanks = NULL;\r
1634     pkt->nblanks = 0;\r
1636     if (ssh->v1_compressing) {\r
1637         unsigned char *compblk;\r
1638         int complen;\r
1639         zlib_compress_block(ssh->cs_comp_ctx,\r
1640                             pkt->data + 12, pkt->length - 12,\r
1641                             &compblk, &complen);\r
1642         ssh_pkt_ensure(pkt, complen + 2);   /* just in case it's got bigger */\r
1643         memcpy(pkt->data + 12, compblk, complen);\r
1644         sfree(compblk);\r
1645         pkt->length = complen + 12;\r
1646     }\r
1648     ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */\r
1649     pkt->length += 4;\r
1650     len = pkt->length - 4 - 8;  /* len(type+data+CRC) */\r
1651     pad = 8 - (len % 8);\r
1652     pktoffs = 8 - pad;\r
1653     biglen = len + pad;         /* len(padding+type+data+CRC) */\r
1655     for (i = pktoffs; i < 4+8; i++)\r
1656         pkt->data[i] = random_byte();\r
1657     crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */\r
1658     PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);\r
1659     PUT_32BIT(pkt->data + pktoffs, len);\r
1661     if (ssh->cipher)\r
1662         ssh->cipher->encrypt(ssh->v1_cipher_ctx,\r
1663                              pkt->data + pktoffs + 4, biglen);\r
1665     if (offset_p) *offset_p = pktoffs;\r
1666     return biglen + 4;          /* len(length+padding+type+data+CRC) */\r
1669 static int s_write(Ssh ssh, void *data, int len)\r
1671     if (ssh->logctx)\r
1672         log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len,\r
1673                    0, NULL, NULL);\r
1674     return sk_write(ssh->s, (char *)data, len);\r
1677 static void s_wrpkt(Ssh ssh, struct Packet *pkt)\r
1679     int len, backlog, offset;\r
1680     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
1681     backlog = s_write(ssh, pkt->data + offset, len);\r
1682     if (backlog > SSH_MAX_BACKLOG)\r
1683         ssh_throttle_all(ssh, 1, backlog);\r
1684     ssh_free_packet(pkt);\r
1687 static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt)\r
1689     int len, offset;\r
1690     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
1691     if (ssh->deferred_len + len > ssh->deferred_size) {\r
1692         ssh->deferred_size = ssh->deferred_len + len + 128;\r
1693         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
1694                                           ssh->deferred_size,\r
1695                                           unsigned char);\r
1696     }\r
1697     memcpy(ssh->deferred_send_data + ssh->deferred_len,\r
1698            pkt->data + offset, len);\r
1699     ssh->deferred_len += len;\r
1700     ssh_free_packet(pkt);\r
1703 /*\r
1704  * Construct a SSH-1 packet with the specified contents.\r
1705  * (This all-at-once interface used to be the only one, but now SSH-1\r
1706  * packets can also be constructed incrementally.)\r
1707  */\r
1708 static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap)\r
1710     int argtype;\r
1711     Bignum bn;\r
1712     struct Packet *pkt;\r
1714     pkt = ssh1_pkt_init(pkttype);\r
1716     while ((argtype = va_arg(ap, int)) != PKT_END) {\r
1717         unsigned char *argp, argchar;\r
1718         char *sargp;\r
1719         unsigned long argint;\r
1720         int arglen;\r
1721         switch (argtype) {\r
1722           /* Actual fields in the packet */\r
1723           case PKT_INT:\r
1724             argint = va_arg(ap, int);\r
1725             ssh_pkt_adduint32(pkt, argint);\r
1726             break;\r
1727           case PKT_CHAR:\r
1728             argchar = (unsigned char) va_arg(ap, int);\r
1729             ssh_pkt_addbyte(pkt, argchar);\r
1730             break;\r
1731           case PKT_DATA:\r
1732             argp = va_arg(ap, unsigned char *);\r
1733             arglen = va_arg(ap, int);\r
1734             ssh_pkt_adddata(pkt, argp, arglen);\r
1735             break;\r
1736           case PKT_STR:\r
1737             sargp = va_arg(ap, char *);\r
1738             ssh_pkt_addstring(pkt, sargp);\r
1739             break;\r
1740           case PKT_BIGNUM:\r
1741             bn = va_arg(ap, Bignum);\r
1742             ssh1_pkt_addmp(pkt, bn);\r
1743             break;\r
1744           /* Tokens for modifications to packet logging */\r
1745           case PKTT_PASSWORD:\r
1746             dont_log_password(ssh, pkt, PKTLOG_BLANK);\r
1747             break;\r
1748           case PKTT_DATA:\r
1749             dont_log_data(ssh, pkt, PKTLOG_OMIT);\r
1750             break;\r
1751           case PKTT_OTHER:\r
1752             end_log_omission(ssh, pkt);\r
1753             break;\r
1754         }\r
1755     }\r
1757     return pkt;\r
1760 static void send_packet(Ssh ssh, int pkttype, ...)\r
1762     struct Packet *pkt;\r
1763     va_list ap;\r
1764     va_start(ap, pkttype);\r
1765     pkt = construct_packet(ssh, pkttype, ap);\r
1766     va_end(ap);\r
1767     s_wrpkt(ssh, pkt);\r
1770 static void defer_packet(Ssh ssh, int pkttype, ...)\r
1772     struct Packet *pkt;\r
1773     va_list ap;\r
1774     va_start(ap, pkttype);\r
1775     pkt = construct_packet(ssh, pkttype, ap);\r
1776     va_end(ap);\r
1777     s_wrpkt_defer(ssh, pkt);\r
1780 static int ssh_versioncmp(char *a, char *b)\r
1782     char *ae, *be;\r
1783     unsigned long av, bv;\r
1785     av = strtoul(a, &ae, 10);\r
1786     bv = strtoul(b, &be, 10);\r
1787     if (av != bv)\r
1788         return (av < bv ? -1 : +1);\r
1789     if (*ae == '.')\r
1790         ae++;\r
1791     if (*be == '.')\r
1792         be++;\r
1793     av = strtoul(ae, &ae, 10);\r
1794     bv = strtoul(be, &be, 10);\r
1795     if (av != bv)\r
1796         return (av < bv ? -1 : +1);\r
1797     return 0;\r
1800 /*\r
1801  * Utility routines for putting an SSH-protocol `string' and\r
1802  * `uint32' into a hash state.\r
1803  */\r
1804 static void hash_string(const struct ssh_hash *h, void *s, void *str, int len)\r
1806     unsigned char lenblk[4];\r
1807     PUT_32BIT(lenblk, len);\r
1808     h->bytes(s, lenblk, 4);\r
1809     h->bytes(s, str, len);\r
1812 static void hash_uint32(const struct ssh_hash *h, void *s, unsigned i)\r
1814     unsigned char intblk[4];\r
1815     PUT_32BIT(intblk, i);\r
1816     h->bytes(s, intblk, 4);\r
1819 /*\r
1820  * Packet construction functions. Mostly shared between SSH-1 and SSH-2.\r
1821  */\r
1822 static void ssh_pkt_ensure(struct Packet *pkt, int length)\r
1824     if (pkt->maxlen < length) {\r
1825         unsigned char *body = pkt->body;\r
1826         int offset = body ? body - pkt->data : 0;\r
1827         pkt->maxlen = length + 256;\r
1828         pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char);\r
1829         if (body) pkt->body = pkt->data + offset;\r
1830     }\r
1832 static void ssh_pkt_adddata(struct Packet *pkt, const void *data, int len)\r
1834     if (pkt->logmode != PKTLOG_EMIT) {\r
1835         pkt->nblanks++;\r
1836         pkt->blanks = sresize(pkt->blanks, pkt->nblanks, struct logblank_t);\r
1837         assert(pkt->body);\r
1838         pkt->blanks[pkt->nblanks-1].offset = pkt->length -\r
1839                                              (pkt->body - pkt->data);\r
1840         pkt->blanks[pkt->nblanks-1].len = len;\r
1841         pkt->blanks[pkt->nblanks-1].type = pkt->logmode;\r
1842     }\r
1843     pkt->length += len;\r
1844     ssh_pkt_ensure(pkt, pkt->length);\r
1845     memcpy(pkt->data + pkt->length - len, data, len);\r
1847 static void ssh_pkt_addbyte(struct Packet *pkt, unsigned char byte)\r
1849     ssh_pkt_adddata(pkt, &byte, 1);\r
1851 static void ssh2_pkt_addbool(struct Packet *pkt, unsigned char value)\r
1853     ssh_pkt_adddata(pkt, &value, 1);\r
1855 static void ssh_pkt_adduint32(struct Packet *pkt, unsigned long value)\r
1857     unsigned char x[4];\r
1858     PUT_32BIT(x, value);\r
1859     ssh_pkt_adddata(pkt, x, 4);\r
1861 static void ssh_pkt_addstring_start(struct Packet *pkt)\r
1863     ssh_pkt_adduint32(pkt, 0);\r
1864     pkt->savedpos = pkt->length;\r
1866 static void ssh_pkt_addstring_str(struct Packet *pkt, const char *data)\r
1868     ssh_pkt_adddata(pkt, data, strlen(data));\r
1869     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);\r
1871 static void ssh_pkt_addstring_data(struct Packet *pkt, const char *data,\r
1872                                    int len)\r
1874     ssh_pkt_adddata(pkt, data, len);\r
1875     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);\r
1877 static void ssh_pkt_addstring(struct Packet *pkt, const char *data)\r
1879     ssh_pkt_addstring_start(pkt);\r
1880     ssh_pkt_addstring_str(pkt, data);\r
1882 static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b)\r
1884     int len = ssh1_bignum_length(b);\r
1885     unsigned char *data = snewn(len, unsigned char);\r
1886     (void) ssh1_write_bignum(data, b);\r
1887     ssh_pkt_adddata(pkt, data, len);\r
1888     sfree(data);\r
1890 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)\r
1892     unsigned char *p;\r
1893     int i, n = (bignum_bitcount(b) + 7) / 8;\r
1894     p = snewn(n + 1, unsigned char);\r
1895     p[0] = 0;\r
1896     for (i = 1; i <= n; i++)\r
1897         p[i] = bignum_byte(b, n - i);\r
1898     i = 0;\r
1899     while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)\r
1900         i++;\r
1901     memmove(p, p + i, n + 1 - i);\r
1902     *len = n + 1 - i;\r
1903     return p;\r
1905 static void ssh2_pkt_addmp(struct Packet *pkt, Bignum b)\r
1907     unsigned char *p;\r
1908     int len;\r
1909     p = ssh2_mpint_fmt(b, &len);\r
1910     ssh_pkt_addstring_start(pkt);\r
1911     ssh_pkt_addstring_data(pkt, (char *)p, len);\r
1912     sfree(p);\r
1915 static struct Packet *ssh1_pkt_init(int pkt_type)\r
1917     struct Packet *pkt = ssh_new_packet();\r
1918     pkt->length = 4 + 8;            /* space for length + max padding */\r
1919     ssh_pkt_addbyte(pkt, pkt_type);\r
1920     pkt->body = pkt->data + pkt->length;\r
1921     return pkt;\r
1924 /* For legacy code (SSH-1 and -2 packet construction used to be separate) */\r
1925 #define ssh2_pkt_ensure(pkt, length) ssh_pkt_ensure(pkt, length)\r
1926 #define ssh2_pkt_adddata(pkt, data, len) ssh_pkt_adddata(pkt, data, len)\r
1927 #define ssh2_pkt_addbyte(pkt, byte) ssh_pkt_addbyte(pkt, byte)\r
1928 #define ssh2_pkt_adduint32(pkt, value) ssh_pkt_adduint32(pkt, value)\r
1929 #define ssh2_pkt_addstring_start(pkt) ssh_pkt_addstring_start(pkt)\r
1930 #define ssh2_pkt_addstring_str(pkt, data) ssh_pkt_addstring_str(pkt, data)\r
1931 #define ssh2_pkt_addstring_data(pkt, data, len) ssh_pkt_addstring_data(pkt, data, len)\r
1932 #define ssh2_pkt_addstring(pkt, data) ssh_pkt_addstring(pkt, data)\r
1934 static struct Packet *ssh2_pkt_init(int pkt_type)\r
1936     struct Packet *pkt = ssh_new_packet();\r
1937     pkt->length = 5; /* space for packet length + padding length */\r
1938     pkt->forcepad = 0;\r
1939     ssh_pkt_addbyte(pkt, (unsigned char) pkt_type);\r
1940     pkt->body = pkt->data + pkt->length; /* after packet type */\r
1941     return pkt;\r
1944 /*\r
1945  * Construct an SSH-2 final-form packet: compress it, encrypt it,\r
1946  * put the MAC on it. Final packet, ready to be sent, is stored in\r
1947  * pkt->data. Total length is returned.\r
1948  */\r
1949 static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt)\r
1951     int cipherblk, maclen, padding, i;\r
1953     if (ssh->logctx)\r
1954         log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],\r
1955                    ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),\r
1956                    pkt->body, pkt->length - (pkt->body - pkt->data),\r
1957                    pkt->nblanks, pkt->blanks, &ssh->v2_outgoing_sequence);\r
1958     sfree(pkt->blanks); pkt->blanks = NULL;\r
1959     pkt->nblanks = 0;\r
1961     /*\r
1962      * Compress packet payload.\r
1963      */\r
1964     {\r
1965         unsigned char *newpayload;\r
1966         int newlen;\r
1967         if (ssh->cscomp &&\r
1968             ssh->cscomp->compress(ssh->cs_comp_ctx, pkt->data + 5,\r
1969                                   pkt->length - 5,\r
1970                                   &newpayload, &newlen)) {\r
1971             pkt->length = 5;\r
1972             ssh2_pkt_adddata(pkt, newpayload, newlen);\r
1973             sfree(newpayload);\r
1974         }\r
1975     }\r
1977     /*\r
1978      * Add padding. At least four bytes, and must also bring total\r
1979      * length (minus MAC) up to a multiple of the block size.\r
1980      * If pkt->forcepad is set, make sure the packet is at least that size\r
1981      * after padding.\r
1982      */\r
1983     cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8;  /* block size */\r
1984     cipherblk = cipherblk < 8 ? 8 : cipherblk;  /* or 8 if blksize < 8 */\r
1985     padding = 4;\r
1986     if (pkt->length + padding < pkt->forcepad)\r
1987         padding = pkt->forcepad - pkt->length;\r
1988     padding +=\r
1989         (cipherblk - (pkt->length + padding) % cipherblk) % cipherblk;\r
1990     assert(padding <= 255);\r
1991     maclen = ssh->csmac ? ssh->csmac->len : 0;\r
1992     ssh2_pkt_ensure(pkt, pkt->length + padding + maclen);\r
1993     pkt->data[4] = padding;\r
1994     for (i = 0; i < padding; i++)\r
1995         pkt->data[pkt->length + i] = random_byte();\r
1996     PUT_32BIT(pkt->data, pkt->length + padding - 4);\r
1997     if (ssh->csmac)\r
1998         ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,\r
1999                              pkt->length + padding,\r
2000                              ssh->v2_outgoing_sequence);\r
2001     ssh->v2_outgoing_sequence++;       /* whether or not we MACed */\r
2003     if (ssh->cscipher)\r
2004         ssh->cscipher->encrypt(ssh->cs_cipher_ctx,\r
2005                                pkt->data, pkt->length + padding);\r
2007     pkt->encrypted_len = pkt->length + padding;\r
2009     /* Ready-to-send packet starts at pkt->data. We return length. */\r
2010     return pkt->length + padding + maclen;\r
2013 /*\r
2014  * Routines called from the main SSH code to send packets. There\r
2015  * are quite a few of these, because we have two separate\r
2016  * mechanisms for delaying the sending of packets:\r
2017  * \r
2018  *  - In order to send an IGNORE message and a password message in\r
2019  *    a single fixed-length blob, we require the ability to\r
2020  *    concatenate the encrypted forms of those two packets _into_ a\r
2021  *    single blob and then pass it to our <network.h> transport\r
2022  *    layer in one go. Hence, there's a deferment mechanism which\r
2023  *    works after packet encryption.\r
2024  * \r
2025  *  - In order to avoid sending any connection-layer messages\r
2026  *    during repeat key exchange, we have to queue up any such\r
2027  *    outgoing messages _before_ they are encrypted (and in\r
2028  *    particular before they're allocated sequence numbers), and\r
2029  *    then send them once we've finished.\r
2030  * \r
2031  * I call these mechanisms `defer' and `queue' respectively, so as\r
2032  * to distinguish them reasonably easily.\r
2033  * \r
2034  * The functions send_noqueue() and defer_noqueue() free the packet\r
2035  * structure they are passed. Every outgoing packet goes through\r
2036  * precisely one of these functions in its life; packets passed to\r
2037  * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of\r
2038  * these or get queued, and then when the queue is later emptied\r
2039  * the packets are all passed to defer_noqueue().\r
2040  *\r
2041  * When using a CBC-mode cipher, it's necessary to ensure that an\r
2042  * attacker can't provide data to be encrypted using an IV that they\r
2043  * know.  We ensure this by prefixing each packet that might contain\r
2044  * user data with an SSH_MSG_IGNORE.  This is done using the deferral\r
2045  * mechanism, so in this case send_noqueue() ends up redirecting to\r
2046  * defer_noqueue().  If you don't like this inefficiency, don't use\r
2047  * CBC.\r
2048  */\r
2050 static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int);\r
2051 static void ssh_pkt_defersend(Ssh);\r
2053 /*\r
2054  * Send an SSH-2 packet immediately, without queuing or deferring.\r
2055  */\r
2056 static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt)\r
2058     int len;\r
2059     int backlog;\r
2060     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) {\r
2061         /* We need to send two packets, so use the deferral mechanism. */\r
2062         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2063         ssh_pkt_defersend(ssh);\r
2064         return;\r
2065     }\r
2066     len = ssh2_pkt_construct(ssh, pkt);\r
2067     backlog = s_write(ssh, pkt->data, len);\r
2068     if (backlog > SSH_MAX_BACKLOG)\r
2069         ssh_throttle_all(ssh, 1, backlog);\r
2071     ssh->outgoing_data_size += pkt->encrypted_len;\r
2072     if (!ssh->kex_in_progress &&\r
2073         ssh->max_data_size != 0 &&\r
2074         ssh->outgoing_data_size > ssh->max_data_size)\r
2075         do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2077     ssh_free_packet(pkt);\r
2080 /*\r
2081  * Defer an SSH-2 packet.\r
2082  */\r
2083 static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore)\r
2085     int len;\r
2086     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) &&\r
2087         ssh->deferred_len == 0 && !noignore &&\r
2088         !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2089         /*\r
2090          * Interpose an SSH_MSG_IGNORE to ensure that user data don't\r
2091          * get encrypted with a known IV.\r
2092          */\r
2093         struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2094         ssh2_pkt_addstring_start(ipkt);\r
2095         ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE);\r
2096     }\r
2097     len = ssh2_pkt_construct(ssh, pkt);\r
2098     if (ssh->deferred_len + len > ssh->deferred_size) {\r
2099         ssh->deferred_size = ssh->deferred_len + len + 128;\r
2100         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
2101                                           ssh->deferred_size,\r
2102                                           unsigned char);\r
2103     }\r
2104     memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->data, len);\r
2105     ssh->deferred_len += len;\r
2106     ssh->deferred_data_size += pkt->encrypted_len;\r
2107     ssh_free_packet(pkt);\r
2110 /*\r
2111  * Queue an SSH-2 packet.\r
2112  */\r
2113 static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt)\r
2115     assert(ssh->queueing);\r
2117     if (ssh->queuelen >= ssh->queuesize) {\r
2118         ssh->queuesize = ssh->queuelen + 32;\r
2119         ssh->queue = sresize(ssh->queue, ssh->queuesize, struct Packet *);\r
2120     }\r
2122     ssh->queue[ssh->queuelen++] = pkt;\r
2125 /*\r
2126  * Either queue or send a packet, depending on whether queueing is\r
2127  * set.\r
2128  */\r
2129 static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt)\r
2131     if (ssh->queueing)\r
2132         ssh2_pkt_queue(ssh, pkt);\r
2133     else\r
2134         ssh2_pkt_send_noqueue(ssh, pkt);\r
2137 /*\r
2138  * Either queue or defer a packet, depending on whether queueing is\r
2139  * set.\r
2140  */\r
2141 static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt)\r
2143     if (ssh->queueing)\r
2144         ssh2_pkt_queue(ssh, pkt);\r
2145     else\r
2146         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2149 /*\r
2150  * Send the whole deferred data block constructed by\r
2151  * ssh2_pkt_defer() or SSH-1's defer_packet().\r
2152  * \r
2153  * The expected use of the defer mechanism is that you call\r
2154  * ssh2_pkt_defer() a few times, then call ssh_pkt_defersend(). If\r
2155  * not currently queueing, this simply sets up deferred_send_data\r
2156  * and then sends it. If we _are_ currently queueing, the calls to\r
2157  * ssh2_pkt_defer() put the deferred packets on to the queue\r
2158  * instead, and therefore ssh_pkt_defersend() has no deferred data\r
2159  * to send. Hence, there's no need to make it conditional on\r
2160  * ssh->queueing.\r
2161  */\r
2162 static void ssh_pkt_defersend(Ssh ssh)\r
2164     int backlog;\r
2165     backlog = s_write(ssh, ssh->deferred_send_data, ssh->deferred_len);\r
2166     ssh->deferred_len = ssh->deferred_size = 0;\r
2167     sfree(ssh->deferred_send_data);\r
2168     ssh->deferred_send_data = NULL;\r
2169     if (backlog > SSH_MAX_BACKLOG)\r
2170         ssh_throttle_all(ssh, 1, backlog);\r
2172     ssh->outgoing_data_size += ssh->deferred_data_size;\r
2173     if (!ssh->kex_in_progress &&\r
2174         ssh->max_data_size != 0 &&\r
2175         ssh->outgoing_data_size > ssh->max_data_size)\r
2176         do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2177     ssh->deferred_data_size = 0;\r
2180 /*\r
2181  * Send a packet whose length needs to be disguised (typically\r
2182  * passwords or keyboard-interactive responses).\r
2183  */\r
2184 static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt,\r
2185                                        int padsize)\r
2187 #if 0\r
2188     if (0) {\r
2189         /*\r
2190          * The simplest way to do this is to adjust the\r
2191          * variable-length padding field in the outgoing packet.\r
2192          * \r
2193          * Currently compiled out, because some Cisco SSH servers\r
2194          * don't like excessively padded packets (bah, why's it\r
2195          * always Cisco?)\r
2196          */\r
2197         pkt->forcepad = padsize;\r
2198         ssh2_pkt_send(ssh, pkt);\r
2199     } else\r
2200 #endif\r
2201     {\r
2202         /*\r
2203          * If we can't do that, however, an alternative approach is\r
2204          * to use the pkt_defer mechanism to bundle the packet\r
2205          * tightly together with an SSH_MSG_IGNORE such that their\r
2206          * combined length is a constant. So first we construct the\r
2207          * final form of this packet and defer its sending.\r
2208          */\r
2209         ssh2_pkt_defer(ssh, pkt);\r
2211         /*\r
2212          * Now construct an SSH_MSG_IGNORE which includes a string\r
2213          * that's an exact multiple of the cipher block size. (If\r
2214          * the cipher is NULL so that the block size is\r
2215          * unavailable, we don't do this trick at all, because we\r
2216          * gain nothing by it.)\r
2217          */\r
2218         if (ssh->cscipher &&\r
2219             !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2220             int stringlen, i;\r
2222             stringlen = (256 - ssh->deferred_len);\r
2223             stringlen += ssh->cscipher->blksize - 1;\r
2224             stringlen -= (stringlen % ssh->cscipher->blksize);\r
2225             if (ssh->cscomp) {\r
2226                 /*\r
2227                  * Temporarily disable actual compression, so we\r
2228                  * can guarantee to get this string exactly the\r
2229                  * length we want it. The compression-disabling\r
2230                  * routine should return an integer indicating how\r
2231                  * many bytes we should adjust our string length\r
2232                  * by.\r
2233                  */\r
2234                 stringlen -=\r
2235                     ssh->cscomp->disable_compression(ssh->cs_comp_ctx);\r
2236             }\r
2237             pkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2238             ssh2_pkt_addstring_start(pkt);\r
2239             for (i = 0; i < stringlen; i++) {\r
2240                 char c = (char) random_byte();\r
2241                 ssh2_pkt_addstring_data(pkt, &c, 1);\r
2242             }\r
2243             ssh2_pkt_defer(ssh, pkt);\r
2244         }\r
2245         ssh_pkt_defersend(ssh);\r
2246     }\r
2249 /*\r
2250  * Send all queued SSH-2 packets. We send them by means of\r
2251  * ssh2_pkt_defer_noqueue(), in case they included a pair of\r
2252  * packets that needed to be lumped together.\r
2253  */\r
2254 static void ssh2_pkt_queuesend(Ssh ssh)\r
2256     int i;\r
2258     assert(!ssh->queueing);\r
2260     for (i = 0; i < ssh->queuelen; i++)\r
2261         ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE);\r
2262     ssh->queuelen = 0;\r
2264     ssh_pkt_defersend(ssh);\r
2267 #if 0\r
2268 void bndebug(char *string, Bignum b)\r
2270     unsigned char *p;\r
2271     int i, len;\r
2272     p = ssh2_mpint_fmt(b, &len);\r
2273     debug(("%s", string));\r
2274     for (i = 0; i < len; i++)\r
2275         debug((" %02x", p[i]));\r
2276     debug(("\n"));\r
2277     sfree(p);\r
2279 #endif\r
2281 static void hash_mpint(const struct ssh_hash *h, void *s, Bignum b)\r
2283     unsigned char *p;\r
2284     int len;\r
2285     p = ssh2_mpint_fmt(b, &len);\r
2286     hash_string(h, s, p, len);\r
2287     sfree(p);\r
2290 /*\r
2291  * Packet decode functions for both SSH-1 and SSH-2.\r
2292  */\r
2293 static unsigned long ssh_pkt_getuint32(struct Packet *pkt)\r
2295     unsigned long value;\r
2296     if (pkt->length - pkt->savedpos < 4)\r
2297         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2298     value = GET_32BIT(pkt->body + pkt->savedpos);\r
2299     pkt->savedpos += 4;\r
2300     return value;\r
2302 static int ssh2_pkt_getbool(struct Packet *pkt)\r
2304     unsigned long value;\r
2305     if (pkt->length - pkt->savedpos < 1)\r
2306         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2307     value = pkt->body[pkt->savedpos] != 0;\r
2308     pkt->savedpos++;\r
2309     return value;\r
2311 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length)\r
2313     int len;\r
2314     *p = NULL;\r
2315     *length = 0;\r
2316     if (pkt->length - pkt->savedpos < 4)\r
2317         return;\r
2318     len = toint(GET_32BIT(pkt->body + pkt->savedpos));\r
2319     if (len < 0)\r
2320         return;\r
2321     *length = len;\r
2322     pkt->savedpos += 4;\r
2323     if (pkt->length - pkt->savedpos < *length)\r
2324         return;\r
2325     *p = (char *)(pkt->body + pkt->savedpos);\r
2326     pkt->savedpos += *length;\r
2328 static void *ssh_pkt_getdata(struct Packet *pkt, int length)\r
2330     if (pkt->length - pkt->savedpos < length)\r
2331         return NULL;\r
2332     pkt->savedpos += length;\r
2333     return pkt->body + (pkt->savedpos - length);\r
2335 static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key,\r
2336                               unsigned char **keystr)\r
2338     int j;\r
2340     j = makekey(pkt->body + pkt->savedpos,\r
2341                 pkt->length - pkt->savedpos,\r
2342                 key, keystr, 0);\r
2344     if (j < 0)\r
2345         return FALSE;\r
2346     \r
2347     pkt->savedpos += j;\r
2348     assert(pkt->savedpos < pkt->length);\r
2350     return TRUE;\r
2352 static Bignum ssh1_pkt_getmp(struct Packet *pkt)\r
2354     int j;\r
2355     Bignum b;\r
2357     j = ssh1_read_bignum(pkt->body + pkt->savedpos,\r
2358                          pkt->length - pkt->savedpos, &b);\r
2360     if (j < 0)\r
2361         return NULL;\r
2363     pkt->savedpos += j;\r
2364     return b;\r
2366 static Bignum ssh2_pkt_getmp(struct Packet *pkt)\r
2368     char *p;\r
2369     int length;\r
2370     Bignum b;\r
2372     ssh_pkt_getstring(pkt, &p, &length);\r
2373     if (!p)\r
2374         return NULL;\r
2375     if (p[0] & 0x80)\r
2376         return NULL;\r
2377     b = bignum_from_bytes((unsigned char *)p, length);\r
2378     return b;\r
2381 /*\r
2382  * Helper function to add an SSH-2 signature blob to a packet.\r
2383  * Expects to be shown the public key blob as well as the signature\r
2384  * blob. Normally works just like ssh2_pkt_addstring, but will\r
2385  * fiddle with the signature packet if necessary for\r
2386  * BUG_SSH2_RSA_PADDING.\r
2387  */\r
2388 static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt,\r
2389                              void *pkblob_v, int pkblob_len,\r
2390                              void *sigblob_v, int sigblob_len)\r
2392     unsigned char *pkblob = (unsigned char *)pkblob_v;\r
2393     unsigned char *sigblob = (unsigned char *)sigblob_v;\r
2395     /* dmemdump(pkblob, pkblob_len); */\r
2396     /* dmemdump(sigblob, sigblob_len); */\r
2398     /*\r
2399      * See if this is in fact an ssh-rsa signature and a buggy\r
2400      * server; otherwise we can just do this the easy way.\r
2401      */\r
2402     if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && pkblob_len > 4+7+4 &&\r
2403         (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {\r
2404         int pos, len, siglen;\r
2406         /*\r
2407          * Find the byte length of the modulus.\r
2408          */\r
2410         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2411         len = toint(GET_32BIT(pkblob+pos)); /* get length of exponent */\r
2412         if (len < 0 || len > pkblob_len - pos - 4)\r
2413             goto give_up;\r
2414         pos += 4 + len;                /* skip over exponent */\r
2415         if (pkblob_len - pos < 4)\r
2416             goto give_up;\r
2417         len = toint(GET_32BIT(pkblob+pos)); /* find length of modulus */\r
2418         if (len < 0 || len > pkblob_len - pos - 4)\r
2419             goto give_up;\r
2420         pos += 4;                      /* find modulus itself */\r
2421         while (len > 0 && pkblob[pos] == 0)\r
2422             len--, pos++;\r
2423         /* debug(("modulus length is %d\n", len)); */\r
2425         /*\r
2426          * Now find the signature integer.\r
2427          */\r
2428         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2429         if (sigblob_len < pos+4)\r
2430             goto give_up;\r
2431         siglen = toint(GET_32BIT(sigblob+pos));\r
2432         if (siglen != sigblob_len - pos - 4)\r
2433             goto give_up;\r
2434         /* debug(("signature length is %d\n", siglen)); */\r
2436         if (len != siglen) {\r
2437             unsigned char newlen[4];\r
2438             ssh2_pkt_addstring_start(pkt);\r
2439             ssh2_pkt_addstring_data(pkt, (char *)sigblob, pos);\r
2440             /* dmemdump(sigblob, pos); */\r
2441             pos += 4;                  /* point to start of actual sig */\r
2442             PUT_32BIT(newlen, len);\r
2443             ssh2_pkt_addstring_data(pkt, (char *)newlen, 4);\r
2444             /* dmemdump(newlen, 4); */\r
2445             newlen[0] = 0;\r
2446             while (len-- > siglen) {\r
2447                 ssh2_pkt_addstring_data(pkt, (char *)newlen, 1);\r
2448                 /* dmemdump(newlen, 1); */\r
2449             }\r
2450             ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen);\r
2451             /* dmemdump(sigblob+pos, siglen); */\r
2452             return;\r
2453         }\r
2455         /* Otherwise fall through and do it the easy way. We also come\r
2456          * here as a fallback if we discover above that the key blob\r
2457          * is misformatted in some way. */\r
2458       give_up:;\r
2459     }\r
2461     ssh2_pkt_addstring_start(pkt);\r
2462     ssh2_pkt_addstring_data(pkt, (char *)sigblob, sigblob_len);\r
2465 /*\r
2466  * Examine the remote side's version string and compare it against\r
2467  * a list of known buggy implementations.\r
2468  */\r
2469 static void ssh_detect_bugs(Ssh ssh, char *vstring)\r
2471     char *imp;                         /* pointer to implementation part */\r
2472     imp = vstring;\r
2473     imp += strcspn(imp, "-");\r
2474     if (*imp) imp++;\r
2475     imp += strcspn(imp, "-");\r
2476     if (*imp) imp++;\r
2478     ssh->remote_bugs = 0;\r
2480     /*\r
2481      * General notes on server version strings:\r
2482      *  - Not all servers reporting "Cisco-1.25" have all the bugs listed\r
2483      *    here -- in particular, we've heard of one that's perfectly happy\r
2484      *    with SSH1_MSG_IGNOREs -- but this string never seems to change,\r
2485      *    so we can't distinguish them.\r
2486      */\r
2487     if (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == FORCE_ON ||\r
2488         (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == AUTO &&\r
2489          (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||\r
2490           !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||\r
2491           !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||\r
2492           !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {\r
2493         /*\r
2494          * These versions don't support SSH1_MSG_IGNORE, so we have\r
2495          * to use a different defence against password length\r
2496          * sniffing.\r
2497          */\r
2498         ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;\r
2499         logevent("We believe remote version has SSH-1 ignore bug");\r
2500     }\r
2502     if (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == FORCE_ON ||\r
2503         (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == AUTO &&\r
2504          (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) {\r
2505         /*\r
2506          * These versions need a plain password sent; they can't\r
2507          * handle having a null and a random length of data after\r
2508          * the password.\r
2509          */\r
2510         ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;\r
2511         logevent("We believe remote version needs a plain SSH-1 password");\r
2512     }\r
2514     if (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == FORCE_ON ||\r
2515         (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == AUTO &&\r
2516          (!strcmp(imp, "Cisco-1.25")))) {\r
2517         /*\r
2518          * These versions apparently have no clue whatever about\r
2519          * RSA authentication and will panic and die if they see\r
2520          * an AUTH_RSA message.\r
2521          */\r
2522         ssh->remote_bugs |= BUG_CHOKES_ON_RSA;\r
2523         logevent("We believe remote version can't handle SSH-1 RSA authentication");\r
2524     }\r
2526     if (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == FORCE_ON ||\r
2527         (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == AUTO &&\r
2528          !wc_match("* VShell", imp) &&\r
2529          (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) ||\r
2530           wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) ||\r
2531           wc_match("2.1 *", imp)))) {\r
2532         /*\r
2533          * These versions have the HMAC bug.\r
2534          */\r
2535         ssh->remote_bugs |= BUG_SSH2_HMAC;\r
2536         logevent("We believe remote version has SSH-2 HMAC bug");\r
2537     }\r
2539     if (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == FORCE_ON ||\r
2540         (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == AUTO &&\r
2541          !wc_match("* VShell", imp) &&\r
2542          (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) {\r
2543         /*\r
2544          * These versions have the key-derivation bug (failing to\r
2545          * include the literal shared secret in the hashes that\r
2546          * generate the keys).\r
2547          */\r
2548         ssh->remote_bugs |= BUG_SSH2_DERIVEKEY;\r
2549         logevent("We believe remote version has SSH-2 key-derivation bug");\r
2550     }\r
2552     if (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == FORCE_ON ||\r
2553         (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == AUTO &&\r
2554          (wc_match("OpenSSH_2.[5-9]*", imp) ||\r
2555           wc_match("OpenSSH_3.[0-2]*", imp)))) {\r
2556         /*\r
2557          * These versions have the SSH-2 RSA padding bug.\r
2558          */\r
2559         ssh->remote_bugs |= BUG_SSH2_RSA_PADDING;\r
2560         logevent("We believe remote version has SSH-2 RSA padding bug");\r
2561     }\r
2563     if (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == FORCE_ON ||\r
2564         (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == AUTO &&\r
2565          wc_match("OpenSSH_2.[0-2]*", imp))) {\r
2566         /*\r
2567          * These versions have the SSH-2 session-ID bug in\r
2568          * public-key authentication.\r
2569          */\r
2570         ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID;\r
2571         logevent("We believe remote version has SSH-2 public-key-session-ID bug");\r
2572     }\r
2574     if (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == FORCE_ON ||\r
2575         (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == AUTO &&\r
2576          (wc_match("DigiSSH_2.0", imp) ||\r
2577           wc_match("OpenSSH_2.[0-4]*", imp) ||\r
2578           wc_match("OpenSSH_2.5.[0-3]*", imp) ||\r
2579           wc_match("Sun_SSH_1.0", imp) ||\r
2580           wc_match("Sun_SSH_1.0.1", imp) ||\r
2581           /* All versions <= 1.2.6 (they changed their format in 1.2.7) */\r
2582           wc_match("WeOnlyDo-*", imp)))) {\r
2583         /*\r
2584          * These versions have the SSH-2 rekey bug.\r
2585          */\r
2586         ssh->remote_bugs |= BUG_SSH2_REKEY;\r
2587         logevent("We believe remote version has SSH-2 rekey bug");\r
2588     }\r
2590     if (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == FORCE_ON ||\r
2591         (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == AUTO &&\r
2592          (wc_match("1.36_sshlib GlobalSCAPE", imp) ||\r
2593           wc_match("1.36 sshlib: GlobalScape", imp)))) {\r
2594         /*\r
2595          * This version ignores our makpkt and needs to be throttled.\r
2596          */\r
2597         ssh->remote_bugs |= BUG_SSH2_MAXPKT;\r
2598         logevent("We believe remote version ignores SSH-2 maximum packet size");\r
2599     }\r
2601     if (conf_get_int(ssh->conf, CONF_sshbug_ignore2) == FORCE_ON) {\r
2602         /*\r
2603          * Servers that don't support SSH2_MSG_IGNORE. Currently,\r
2604          * none detected automatically.\r
2605          */\r
2606         ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;\r
2607         logevent("We believe remote version has SSH-2 ignore bug");\r
2608     }\r
2610     if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) {\r
2611         /*\r
2612          * Servers that don't support our winadj request for one\r
2613          * reason or another. Currently, none detected automatically.\r
2614          */\r
2615         ssh->remote_bugs |= BUG_CHOKES_ON_WINADJ;\r
2616         logevent("We believe remote version has winadj bug");\r
2617     }\r
2620 /*\r
2621  * The `software version' part of an SSH version string is required\r
2622  * to contain no spaces or minus signs.\r
2623  */\r
2624 static void ssh_fix_verstring(char *str)\r
2626     /* Eat "SSH-<protoversion>-". */\r
2627     assert(*str == 'S'); str++;\r
2628     assert(*str == 'S'); str++;\r
2629     assert(*str == 'H'); str++;\r
2630     assert(*str == '-'); str++;\r
2631     while (*str && *str != '-') str++;\r
2632     assert(*str == '-'); str++;\r
2634     /* Convert minus signs and spaces in the remaining string into\r
2635      * underscores. */\r
2636     while (*str) {\r
2637         if (*str == '-' || *str == ' ')\r
2638             *str = '_';\r
2639         str++;\r
2640     }\r
2643 /*\r
2644  * Send an appropriate SSH version string.\r
2645  */\r
2646 static void ssh_send_verstring(Ssh ssh, char *svers)\r
2648     char *verstring;\r
2650     if (ssh->version == 2) {\r
2651         /*\r
2652          * Construct a v2 version string.\r
2653          */\r
2654         verstring = dupprintf("SSH-2.0-%s\015\012", sshver);\r
2655     } else {\r
2656         /*\r
2657          * Construct a v1 version string.\r
2658          */\r
2659         verstring = dupprintf("SSH-%s-%s\012",\r
2660                               (ssh_versioncmp(svers, "1.5") <= 0 ?\r
2661                                svers : "1.5"),\r
2662                               sshver);\r
2663     }\r
2665     ssh_fix_verstring(verstring);\r
2667     if (ssh->version == 2) {\r
2668         size_t len;\r
2669         /*\r
2670          * Record our version string.\r
2671          */\r
2672         len = strcspn(verstring, "\015\012");\r
2673         ssh->v_c = snewn(len + 1, char);\r
2674         memcpy(ssh->v_c, verstring, len);\r
2675         ssh->v_c[len] = 0;\r
2676     }\r
2678     logeventf(ssh, "We claim version: %.*s",\r
2679               strcspn(verstring, "\015\012"), verstring);\r
2680     s_write(ssh, verstring, strlen(verstring));\r
2681     sfree(verstring);\r
2684 static int do_ssh_init(Ssh ssh, unsigned char c)\r
2686     struct do_ssh_init_state {\r
2687         int crLine;\r
2688         int vslen;\r
2689         char version[10];\r
2690         char *vstring;\r
2691         int vstrsize;\r
2692         int i;\r
2693         int proto1, proto2;\r
2694     };\r
2695     crState(do_ssh_init_state);\r
2696     \r
2697     crBeginState;\r
2699     /* Search for a line beginning with the string "SSH-" in the input. */\r
2700     for (;;) {\r
2701         if (c != 'S') goto no;\r
2702         crReturn(1);\r
2703         if (c != 'S') goto no;\r
2704         crReturn(1);\r
2705         if (c != 'H') goto no;\r
2706         crReturn(1);\r
2707         if (c != '-') goto no;\r
2708         break;\r
2709       no:\r
2710         while (c != '\012')\r
2711             crReturn(1);\r
2712         crReturn(1);\r
2713     }\r
2715     s->vstrsize = 16;\r
2716     s->vstring = snewn(s->vstrsize, char);\r
2717     strcpy(s->vstring, "SSH-");\r
2718     s->vslen = 4;\r
2719     s->i = 0;\r
2720     while (1) {\r
2721         crReturn(1);                   /* get another char */\r
2722         if (s->vslen >= s->vstrsize - 1) {\r
2723             s->vstrsize += 16;\r
2724             s->vstring = sresize(s->vstring, s->vstrsize, char);\r
2725         }\r
2726         s->vstring[s->vslen++] = c;\r
2727         if (s->i >= 0) {\r
2728             if (c == '-') {\r
2729                 s->version[s->i] = '\0';\r
2730                 s->i = -1;\r
2731             } else if (s->i < sizeof(s->version) - 1)\r
2732                 s->version[s->i++] = c;\r
2733         } else if (c == '\012')\r
2734             break;\r
2735     }\r
2737     ssh->agentfwd_enabled = FALSE;\r
2738     ssh->rdpkt2_state.incoming_sequence = 0;\r
2740     s->vstring[s->vslen] = 0;\r
2741     s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */\r
2742     logeventf(ssh, "Server version: %s", s->vstring);\r
2743     ssh_detect_bugs(ssh, s->vstring);\r
2745     /*\r
2746      * Decide which SSH protocol version to support.\r
2747      */\r
2749     /* Anything strictly below "2.0" means protocol 1 is supported. */\r
2750     s->proto1 = ssh_versioncmp(s->version, "2.0") < 0;\r
2751     /* Anything greater or equal to "1.99" means protocol 2 is supported. */\r
2752     s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;\r
2754     if (conf_get_int(ssh->conf, CONF_sshprot) == 0 && !s->proto1) {\r
2755         bombout(("SSH protocol version 1 required by user but not provided by server"));\r
2756         crStop(0);\r
2757     }\r
2758     if (conf_get_int(ssh->conf, CONF_sshprot) == 3 && !s->proto2) {\r
2759         bombout(("SSH protocol version 2 required by user but not provided by server"));\r
2760         crStop(0);\r
2761     }\r
2763     if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1))\r
2764         ssh->version = 2;\r
2765     else\r
2766         ssh->version = 1;\r
2768     logeventf(ssh, "Using SSH protocol version %d", ssh->version);\r
2770     /* Send the version string, if we haven't already */\r
2771     if (conf_get_int(ssh->conf, CONF_sshprot) != 3)\r
2772         ssh_send_verstring(ssh, s->version);\r
2774     if (ssh->version == 2) {\r
2775         size_t len;\r
2776         /*\r
2777          * Record their version string.\r
2778          */\r
2779         len = strcspn(s->vstring, "\015\012");\r
2780         ssh->v_s = snewn(len + 1, char);\r
2781         memcpy(ssh->v_s, s->vstring, len);\r
2782         ssh->v_s[len] = 0;\r
2783             \r
2784         /*\r
2785          * Initialise SSH-2 protocol.\r
2786          */\r
2787         ssh->protocol = ssh2_protocol;\r
2788         ssh2_protocol_setup(ssh);\r
2789         ssh->s_rdpkt = ssh2_rdpkt;\r
2790     } else {\r
2791         /*\r
2792          * Initialise SSH-1 protocol.\r
2793          */\r
2794         ssh->protocol = ssh1_protocol;\r
2795         ssh1_protocol_setup(ssh);\r
2796         ssh->s_rdpkt = ssh1_rdpkt;\r
2797     }\r
2798     if (ssh->version == 2)\r
2799         do_ssh2_transport(ssh, NULL, -1, NULL);\r
2801     update_specials_menu(ssh->frontend);\r
2802     ssh->state = SSH_STATE_BEFORE_SIZE;\r
2803     ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh);\r
2805     sfree(s->vstring);\r
2807     crFinish(0);\r
2810 static void ssh_process_incoming_data(Ssh ssh,\r
2811                                       unsigned char **data, int *datalen)\r
2813     struct Packet *pktin;\r
2815     pktin = ssh->s_rdpkt(ssh, data, datalen);\r
2816     if (pktin) {\r
2817         ssh->protocol(ssh, NULL, 0, pktin);\r
2818         ssh_free_packet(pktin);\r
2819     }\r
2822 static void ssh_queue_incoming_data(Ssh ssh,\r
2823                                     unsigned char **data, int *datalen)\r
2825     bufchain_add(&ssh->queued_incoming_data, *data, *datalen);\r
2826     *data += *datalen;\r
2827     *datalen = 0;\r
2830 static void ssh_process_queued_incoming_data(Ssh ssh)\r
2832     void *vdata;\r
2833     unsigned char *data;\r
2834     int len, origlen;\r
2836     while (!ssh->frozen && bufchain_size(&ssh->queued_incoming_data)) {\r
2837         bufchain_prefix(&ssh->queued_incoming_data, &vdata, &len);\r
2838         data = vdata;\r
2839         origlen = len;\r
2841         while (!ssh->frozen && len > 0)\r
2842             ssh_process_incoming_data(ssh, &data, &len);\r
2844         if (origlen > len)\r
2845             bufchain_consume(&ssh->queued_incoming_data, origlen - len);\r
2846     }\r
2849 static void ssh_set_frozen(Ssh ssh, int frozen)\r
2851     if (ssh->s)\r
2852         sk_set_frozen(ssh->s, frozen);\r
2853     ssh->frozen = frozen;\r
2856 static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)\r
2858     /* Log raw data, if we're in that mode. */\r
2859     if (ssh->logctx)\r
2860         log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,\r
2861                    0, NULL, NULL);\r
2863     crBegin(ssh->ssh_gotdata_crstate);\r
2865     /*\r
2866      * To begin with, feed the characters one by one to the\r
2867      * protocol initialisation / selection function do_ssh_init().\r
2868      * When that returns 0, we're done with the initial greeting\r
2869      * exchange and can move on to packet discipline.\r
2870      */\r
2871     while (1) {\r
2872         int ret;                       /* need not be kept across crReturn */\r
2873         if (datalen == 0)\r
2874             crReturnV;                 /* more data please */\r
2875         ret = do_ssh_init(ssh, *data);\r
2876         data++;\r
2877         datalen--;\r
2878         if (ret == 0)\r
2879             break;\r
2880     }\r
2882     /*\r
2883      * We emerge from that loop when the initial negotiation is\r
2884      * over and we have selected an s_rdpkt function. Now pass\r
2885      * everything to s_rdpkt, and then pass the resulting packets\r
2886      * to the proper protocol handler.\r
2887      */\r
2889     while (1) {\r
2890         while (bufchain_size(&ssh->queued_incoming_data) > 0 || datalen > 0) {\r
2891             if (ssh->frozen) {\r
2892                 ssh_queue_incoming_data(ssh, &data, &datalen);\r
2893                 /* This uses up all data and cannot cause anything interesting\r
2894                  * to happen; indeed, for anything to happen at all, we must\r
2895                  * return, so break out. */\r
2896                 break;\r
2897             } else if (bufchain_size(&ssh->queued_incoming_data) > 0) {\r
2898                 /* This uses up some or all data, and may freeze the\r
2899                  * session. */\r
2900                 ssh_process_queued_incoming_data(ssh);\r
2901             } else {\r
2902                 /* This uses up some or all data, and may freeze the\r
2903                  * session. */\r
2904                 ssh_process_incoming_data(ssh, &data, &datalen);\r
2905             }\r
2906             /* FIXME this is probably EBW. */\r
2907             if (ssh->state == SSH_STATE_CLOSED)\r
2908                 return;\r
2909         }\r
2910         /* We're out of data. Go and get some more. */\r
2911         crReturnV;\r
2912     }\r
2913     crFinishV;\r
2916 static int ssh_do_close(Ssh ssh, int notify_exit)\r
2918     int ret = 0;\r
2919     struct ssh_channel *c;\r
2921     ssh->state = SSH_STATE_CLOSED;\r
2922     expire_timer_context(ssh);\r
2923     if (ssh->s) {\r
2924         sk_close(ssh->s);\r
2925         ssh->s = NULL;\r
2926         if (notify_exit)\r
2927             notify_remote_exit(ssh->frontend);\r
2928         else\r
2929             ret = 1;\r
2930     }\r
2931     /*\r
2932      * Now we must shut down any port- and X-forwarded channels going\r
2933      * through this connection.\r
2934      */\r
2935     if (ssh->channels) {\r
2936         while (NULL != (c = index234(ssh->channels, 0))) {\r
2937             switch (c->type) {\r
2938               case CHAN_X11:\r
2939                 x11_close(c->u.x11.s);\r
2940                 break;\r
2941               case CHAN_SOCKDATA:\r
2942               case CHAN_SOCKDATA_DORMANT:\r
2943                 pfd_close(c->u.pfd.s);\r
2944                 break;\r
2945             }\r
2946             del234(ssh->channels, c); /* moving next one to index 0 */\r
2947             if (ssh->version == 2)\r
2948                 bufchain_clear(&c->v.v2.outbuffer);\r
2949             sfree(c);\r
2950         }\r
2951     }\r
2952     /*\r
2953      * Go through port-forwardings, and close any associated\r
2954      * listening sockets.\r
2955      */\r
2956     if (ssh->portfwds) {\r
2957         struct ssh_portfwd *pf;\r
2958         while (NULL != (pf = index234(ssh->portfwds, 0))) {\r
2959             /* Dispose of any listening socket. */\r
2960             if (pf->local)\r
2961                 pfd_terminate(pf->local);\r
2962             del234(ssh->portfwds, pf); /* moving next one to index 0 */\r
2963             free_portfwd(pf);\r
2964         }\r
2965         freetree234(ssh->portfwds);\r
2966         ssh->portfwds = NULL;\r
2967     }\r
2969     return ret;\r
2972 static void ssh_log(Plug plug, int type, SockAddr addr, int port,\r
2973                     const char *error_msg, int error_code)\r
2975     Ssh ssh = (Ssh) plug;\r
2976     char addrbuf[256], *msg;\r
2978     sk_getaddr(addr, addrbuf, lenof(addrbuf));\r
2980     if (type == 0)\r
2981         msg = dupprintf("Connecting to %s port %d", addrbuf, port);\r
2982     else\r
2983         msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);\r
2985     logevent(msg);\r
2986     sfree(msg);\r
2989 static int ssh_closing(Plug plug, const char *error_msg, int error_code,\r
2990                        int calling_back)\r
2992     Ssh ssh = (Ssh) plug;\r
2993     int need_notify = ssh_do_close(ssh, FALSE);\r
2995     if (!error_msg) {\r
2996         if (!ssh->close_expected)\r
2997             error_msg = "Server unexpectedly closed network connection";\r
2998         else\r
2999             error_msg = "Server closed network connection";\r
3000     }\r
3002     if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0)\r
3003         ssh->exitcode = 0;\r
3005     if (need_notify)\r
3006         notify_remote_exit(ssh->frontend);\r
3008     if (error_msg)\r
3009         logevent(error_msg);\r
3010     if (!ssh->close_expected || !ssh->clean_exit)\r
3011         connection_fatal(ssh->frontend, "%s", error_msg);\r
3012     return 0;\r
3015 static int ssh_receive(Plug plug, int urgent, char *data, int len)\r
3017     Ssh ssh = (Ssh) plug;\r
3018     ssh_gotdata(ssh, (unsigned char *)data, len);\r
3019     if (ssh->state == SSH_STATE_CLOSED) {\r
3020         ssh_do_close(ssh, TRUE);\r
3021         return 0;\r
3022     }\r
3023     return 1;\r
3026 static void ssh_sent(Plug plug, int bufsize)\r
3028     Ssh ssh = (Ssh) plug;\r
3029     /*\r
3030      * If the send backlog on the SSH socket itself clears, we\r
3031      * should unthrottle the whole world if it was throttled.\r
3032      */\r
3033     if (bufsize < SSH_MAX_BACKLOG)\r
3034         ssh_throttle_all(ssh, 0, bufsize);\r
3037 /*\r
3038  * Connect to specified host and port.\r
3039  * Returns an error message, or NULL on success.\r
3040  * Also places the canonical host name into `realhost'. It must be\r
3041  * freed by the caller.\r
3042  */\r
3043 static const char *connect_to_host(Ssh ssh, char *host, int port,\r
3044                                    char **realhost, int nodelay, int keepalive)\r
3046     static const struct plug_function_table fn_table = {\r
3047         ssh_log,\r
3048         ssh_closing,\r
3049         ssh_receive,\r
3050         ssh_sent,\r
3051         NULL\r
3052     };\r
3054     SockAddr addr;\r
3055     const char *err;\r
3056     char *loghost;\r
3057     int addressfamily, sshprot;\r
3058     \r
3059     loghost = conf_get_str(ssh->conf, CONF_loghost);\r
3060     if (*loghost) {\r
3061         char *colon;\r
3063         ssh->savedhost = dupstr(loghost);\r
3064         ssh->savedport = 22;           /* default ssh port */\r
3066         /*\r
3067          * A colon suffix on savedhost also lets us affect\r
3068          * savedport.\r
3069          * \r
3070          * (FIXME: do something about IPv6 address literals here.)\r
3071          */\r
3072         colon = strrchr(ssh->savedhost, ':');\r
3073         if (colon) {\r
3074             *colon++ = '\0';\r
3075             if (*colon)\r
3076                 ssh->savedport = atoi(colon);\r
3077         }\r
3078     } else {\r
3079         ssh->savedhost = dupstr(host);\r
3080         if (port < 0)\r
3081             port = 22;                 /* default ssh port */\r
3082         ssh->savedport = port;\r
3083     }\r
3085     /*\r
3086      * Try to find host.\r
3087      */\r
3088     addressfamily = conf_get_int(ssh->conf, CONF_addressfamily);\r
3089     logeventf(ssh, "Looking up host \"%s\"%s", host,\r
3090               (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :\r
3091                (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : "")));\r
3092     addr = name_lookup(host, port, realhost, ssh->conf, addressfamily);\r
3093     if ((err = sk_addr_error(addr)) != NULL) {\r
3094         sk_addr_free(addr);\r
3095         return err;\r
3096     }\r
3097     ssh->fullhostname = dupstr(*realhost);   /* save in case of GSSAPI */\r
3099     /*\r
3100      * Open socket.\r
3101      */\r
3102     ssh->fn = &fn_table;\r
3103     ssh->s = new_connection(addr, *realhost, port,\r
3104                             0, 1, nodelay, keepalive, (Plug) ssh, ssh->conf);\r
3105     if ((err = sk_socket_error(ssh->s)) != NULL) {\r
3106         ssh->s = NULL;\r
3107         notify_remote_exit(ssh->frontend);\r
3108         return err;\r
3109     }\r
3111     /*\r
3112      * If the SSH version number's fixed, set it now, and if it's SSH-2,\r
3113      * send the version string too.\r
3114      */\r
3115     sshprot = conf_get_int(ssh->conf, CONF_sshprot);\r
3116     if (sshprot == 0)\r
3117         ssh->version = 1;\r
3118     if (sshprot == 3) {\r
3119         ssh->version = 2;\r
3120         ssh_send_verstring(ssh, NULL);\r
3121     }\r
3123     /*\r
3124      * loghost, if configured, overrides realhost.\r
3125      */\r
3126     if (*loghost) {\r
3127         sfree(*realhost);\r
3128         *realhost = dupstr(loghost);\r
3129     }\r
3131     return NULL;\r
3134 /*\r
3135  * Throttle or unthrottle the SSH connection.\r
3136  */\r
3137 static void ssh_throttle_conn(Ssh ssh, int adjust)\r
3139     int old_count = ssh->conn_throttle_count;\r
3140     ssh->conn_throttle_count += adjust;\r
3141     assert(ssh->conn_throttle_count >= 0);\r
3142     if (ssh->conn_throttle_count && !old_count) {\r
3143         ssh_set_frozen(ssh, 1);\r
3144     } else if (!ssh->conn_throttle_count && old_count) {\r
3145         ssh_set_frozen(ssh, 0);\r
3146     }\r
3149 /*\r
3150  * Throttle or unthrottle _all_ local data streams (for when sends\r
3151  * on the SSH connection itself back up).\r
3152  */\r
3153 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize)\r
3155     int i;\r
3156     struct ssh_channel *c;\r
3158     if (enable == ssh->throttled_all)\r
3159         return;\r
3160     ssh->throttled_all = enable;\r
3161     ssh->overall_bufsize = bufsize;\r
3162     if (!ssh->channels)\r
3163         return;\r
3164     for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) {\r
3165         switch (c->type) {\r
3166           case CHAN_MAINSESSION:\r
3167             /*\r
3168              * This is treated separately, outside the switch.\r
3169              */\r
3170             break;\r
3171           case CHAN_X11:\r
3172             x11_override_throttle(c->u.x11.s, enable);\r
3173             break;\r
3174           case CHAN_AGENT:\r
3175             /* Agent channels require no buffer management. */\r
3176             break;\r
3177           case CHAN_SOCKDATA:\r
3178             pfd_override_throttle(c->u.pfd.s, enable);\r
3179             break;\r
3180         }\r
3181     }\r
3184 static void ssh_agent_callback(void *sshv, void *reply, int replylen)\r
3186     Ssh ssh = (Ssh) sshv;\r
3188     ssh->agent_response = reply;\r
3189     ssh->agent_response_len = replylen;\r
3191     if (ssh->version == 1)\r
3192         do_ssh1_login(ssh, NULL, -1, NULL);\r
3193     else\r
3194         do_ssh2_authconn(ssh, NULL, -1, NULL);\r
3197 static void ssh_dialog_callback(void *sshv, int ret)\r
3199     Ssh ssh = (Ssh) sshv;\r
3201     ssh->user_response = ret;\r
3203     if (ssh->version == 1)\r
3204         do_ssh1_login(ssh, NULL, -1, NULL);\r
3205     else\r
3206         do_ssh2_transport(ssh, NULL, -1, NULL);\r
3208     /*\r
3209      * This may have unfrozen the SSH connection, so do a\r
3210      * queued-data run.\r
3211      */\r
3212     ssh_process_queued_incoming_data(ssh);\r
3215 static void ssh_agentf_callback(void *cv, void *reply, int replylen)\r
3217     struct ssh_channel *c = (struct ssh_channel *)cv;\r
3218     Ssh ssh = c->ssh;\r
3219     void *sentreply = reply;\r
3221     c->u.a.outstanding_requests--;\r
3222     if (!sentreply) {\r
3223         /* Fake SSH_AGENT_FAILURE. */\r
3224         sentreply = "\0\0\0\1\5";\r
3225         replylen = 5;\r
3226     }\r
3227     if (ssh->version == 2) {\r
3228         ssh2_add_channel_data(c, sentreply, replylen);\r
3229         ssh2_try_send(c);\r
3230     } else {\r
3231         send_packet(ssh, SSH1_MSG_CHANNEL_DATA,\r
3232                     PKT_INT, c->remoteid,\r
3233                     PKT_INT, replylen,\r
3234                     PKTT_DATA,\r
3235                     PKT_DATA, sentreply, replylen,\r
3236                     PKTT_OTHER,\r
3237                     PKT_END);\r
3238     }\r
3239     if (reply)\r
3240         sfree(reply);\r
3241     /*\r
3242      * If we've already seen an incoming EOF but haven't sent an\r
3243      * outgoing one, this may be the moment to send it.\r
3244      */\r
3245     if (c->u.a.outstanding_requests == 0 && (c->closes & CLOSES_RCVD_EOF))\r
3246         sshfwd_write_eof(c);\r
3249 /*\r
3250  * Client-initiated disconnection. Send a DISCONNECT if `wire_reason'\r
3251  * non-NULL, otherwise just close the connection. `client_reason' == NULL\r
3252  * => log `wire_reason'.\r
3253  */\r
3254 static void ssh_disconnect(Ssh ssh, char *client_reason, char *wire_reason,\r
3255                            int code, int clean_exit)\r
3257     char *error;\r
3258     if (!client_reason)\r
3259         client_reason = wire_reason;\r
3260     if (client_reason)\r
3261         error = dupprintf("Disconnected: %s", client_reason);\r
3262     else\r
3263         error = dupstr("Disconnected");\r
3264     if (wire_reason) {\r
3265         if (ssh->version == 1) {\r
3266             send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason,\r
3267                         PKT_END);\r
3268         } else if (ssh->version == 2) {\r
3269             struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT);\r
3270             ssh2_pkt_adduint32(pktout, code);\r
3271             ssh2_pkt_addstring(pktout, wire_reason);\r
3272             ssh2_pkt_addstring(pktout, "en");   /* language tag */\r
3273             ssh2_pkt_send_noqueue(ssh, pktout);\r
3274         }\r
3275     }\r
3276     ssh->close_expected = TRUE;\r
3277     ssh->clean_exit = clean_exit;\r
3278     ssh_closing((Plug)ssh, error, 0, 0);\r
3279     sfree(error);\r
3282 /*\r
3283  * Handle the key exchange and user authentication phases.\r
3284  */\r
3285 static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,\r
3286                          struct Packet *pktin)\r
3288     int i, j, ret;\r
3289     unsigned char cookie[8], *ptr;\r
3290     struct MD5Context md5c;\r
3291     struct do_ssh1_login_state {\r
3292         int crLine;\r
3293         int len;\r
3294         unsigned char *rsabuf, *keystr1, *keystr2;\r
3295         unsigned long supported_ciphers_mask, supported_auths_mask;\r
3296         int tried_publickey, tried_agent;\r
3297         int tis_auth_refused, ccard_auth_refused;\r
3298         unsigned char session_id[16];\r
3299         int cipher_type;\r
3300         void *publickey_blob;\r
3301         int publickey_bloblen;\r
3302         char *publickey_comment;\r
3303         int publickey_encrypted;\r
3304         prompts_t *cur_prompt;\r
3305         char c;\r
3306         int pwpkt_type;\r
3307         unsigned char request[5], *response, *p;\r
3308         int responselen;\r
3309         int keyi, nkeys;\r
3310         int authed;\r
3311         struct RSAKey key;\r
3312         Bignum challenge;\r
3313         char *commentp;\r
3314         int commentlen;\r
3315         int dlgret;\r
3316         Filename *keyfile;\r
3317         struct RSAKey servkey, hostkey;\r
3318     };\r
3319     crState(do_ssh1_login_state);\r
3321     crBeginState;\r
3323     if (!pktin)\r
3324         crWaitUntil(pktin);\r
3326     if (pktin->type != SSH1_SMSG_PUBLIC_KEY) {\r
3327         bombout(("Public key packet not received"));\r
3328         crStop(0);\r
3329     }\r
3331     logevent("Received public keys");\r
3333     ptr = ssh_pkt_getdata(pktin, 8);\r
3334     if (!ptr) {\r
3335         bombout(("SSH-1 public key packet stopped before random cookie"));\r
3336         crStop(0);\r
3337     }\r
3338     memcpy(cookie, ptr, 8);\r
3340     if (!ssh1_pkt_getrsakey(pktin, &s->servkey, &s->keystr1) ||\r
3341         !ssh1_pkt_getrsakey(pktin, &s->hostkey, &s->keystr2)) { \r
3342         bombout(("Failed to read SSH-1 public keys from public key packet"));\r
3343         crStop(0);\r
3344     }\r
3346     /*\r
3347      * Log the host key fingerprint.\r
3348      */\r
3349     {\r
3350         char logmsg[80];\r
3351         logevent("Host key fingerprint is:");\r
3352         strcpy(logmsg, "      ");\r
3353         s->hostkey.comment = NULL;\r
3354         rsa_fingerprint(logmsg + strlen(logmsg),\r
3355                         sizeof(logmsg) - strlen(logmsg), &s->hostkey);\r
3356         logevent(logmsg);\r
3357     }\r
3359     ssh->v1_remote_protoflags = ssh_pkt_getuint32(pktin);\r
3360     s->supported_ciphers_mask = ssh_pkt_getuint32(pktin);\r
3361     s->supported_auths_mask = ssh_pkt_getuint32(pktin);\r
3362     if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA))\r
3363         s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA);\r
3365     ssh->v1_local_protoflags =\r
3366         ssh->v1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED;\r
3367     ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;\r
3369     MD5Init(&md5c);\r
3370     MD5Update(&md5c, s->keystr2, s->hostkey.bytes);\r
3371     MD5Update(&md5c, s->keystr1, s->servkey.bytes);\r
3372     MD5Update(&md5c, cookie, 8);\r
3373     MD5Final(s->session_id, &md5c);\r
3375     for (i = 0; i < 32; i++)\r
3376         ssh->session_key[i] = random_byte();\r
3378     /*\r
3379      * Verify that the `bits' and `bytes' parameters match.\r
3380      */\r
3381     if (s->hostkey.bits > s->hostkey.bytes * 8 ||\r
3382         s->servkey.bits > s->servkey.bytes * 8) {\r
3383         bombout(("SSH-1 public keys were badly formatted"));\r
3384         crStop(0);\r
3385     }\r
3387     s->len = (s->hostkey.bytes > s->servkey.bytes ?\r
3388               s->hostkey.bytes : s->servkey.bytes);\r
3390     s->rsabuf = snewn(s->len, unsigned char);\r
3392     /*\r
3393      * Verify the host key.\r
3394      */\r
3395     {\r
3396         /*\r
3397          * First format the key into a string.\r
3398          */\r
3399         int len = rsastr_len(&s->hostkey);\r
3400         char fingerprint[100];\r
3401         char *keystr = snewn(len, char);\r
3402         rsastr_fmt(keystr, &s->hostkey);\r
3403         rsa_fingerprint(fingerprint, sizeof(fingerprint), &s->hostkey);\r
3405         ssh_set_frozen(ssh, 1);\r
3406         s->dlgret = verify_ssh_host_key(ssh->frontend,\r
3407                                         ssh->savedhost, ssh->savedport,\r
3408                                         "rsa", keystr, fingerprint,\r
3409                                         ssh_dialog_callback, ssh);\r
3410         sfree(keystr);\r
3411         if (s->dlgret < 0) {\r
3412             do {\r
3413                 crReturn(0);\r
3414                 if (pktin) {\r
3415                     bombout(("Unexpected data from server while waiting"\r
3416                              " for user host key response"));\r
3417                     crStop(0);\r
3418                 }\r
3419             } while (pktin || inlen > 0);\r
3420             s->dlgret = ssh->user_response;\r
3421         }\r
3422         ssh_set_frozen(ssh, 0);\r
3424         if (s->dlgret == 0) {\r
3425             ssh_disconnect(ssh, "User aborted at host key verification",\r
3426                            NULL, 0, TRUE);\r
3427             crStop(0);\r
3428         }\r
3429     }\r
3431     for (i = 0; i < 32; i++) {\r
3432         s->rsabuf[i] = ssh->session_key[i];\r
3433         if (i < 16)\r
3434             s->rsabuf[i] ^= s->session_id[i];\r
3435     }\r
3437     if (s->hostkey.bytes > s->servkey.bytes) {\r
3438         ret = rsaencrypt(s->rsabuf, 32, &s->servkey);\r
3439         if (ret)\r
3440             ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);\r
3441     } else {\r
3442         ret = rsaencrypt(s->rsabuf, 32, &s->hostkey);\r
3443         if (ret)\r
3444             ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);\r
3445     }\r
3446     if (!ret) {\r
3447         bombout(("SSH-1 public key encryptions failed due to bad formatting"));\r
3448         crStop(0);      \r
3449     }\r
3451     logevent("Encrypted session key");\r
3453     {\r
3454         int cipher_chosen = 0, warn = 0;\r
3455         char *cipher_string = NULL;\r
3456         int i;\r
3457         for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) {\r
3458             int next_cipher = conf_get_int_int(ssh->conf,\r
3459                                                CONF_ssh_cipherlist, i);\r
3460             if (next_cipher == CIPHER_WARN) {\r
3461                 /* If/when we choose a cipher, warn about it */\r
3462                 warn = 1;\r
3463             } else if (next_cipher == CIPHER_AES) {\r
3464                 /* XXX Probably don't need to mention this. */\r
3465                 logevent("AES not supported in SSH-1, skipping");\r
3466             } else {\r
3467                 switch (next_cipher) {\r
3468                   case CIPHER_3DES:     s->cipher_type = SSH_CIPHER_3DES;\r
3469                                         cipher_string = "3DES"; break;\r
3470                   case CIPHER_BLOWFISH: s->cipher_type = SSH_CIPHER_BLOWFISH;\r
3471                                         cipher_string = "Blowfish"; break;\r
3472                   case CIPHER_DES:      s->cipher_type = SSH_CIPHER_DES;\r
3473                                         cipher_string = "single-DES"; break;\r
3474                 }\r
3475                 if (s->supported_ciphers_mask & (1 << s->cipher_type))\r
3476                     cipher_chosen = 1;\r
3477             }\r
3478         }\r
3479         if (!cipher_chosen) {\r
3480             if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0)\r
3481                 bombout(("Server violates SSH-1 protocol by not "\r
3482                          "supporting 3DES encryption"));\r
3483             else\r
3484                 /* shouldn't happen */\r
3485                 bombout(("No supported ciphers found"));\r
3486             crStop(0);\r
3487         }\r
3489         /* Warn about chosen cipher if necessary. */\r
3490         if (warn) {\r
3491             ssh_set_frozen(ssh, 1);\r
3492             s->dlgret = askalg(ssh->frontend, "cipher", cipher_string,\r
3493                                ssh_dialog_callback, ssh);\r
3494             if (s->dlgret < 0) {\r
3495                 do {\r
3496                     crReturn(0);\r
3497                     if (pktin) {\r
3498                         bombout(("Unexpected data from server while waiting"\r
3499                                  " for user response"));\r
3500                         crStop(0);\r
3501                     }\r
3502                 } while (pktin || inlen > 0);\r
3503                 s->dlgret = ssh->user_response;\r
3504             }\r
3505             ssh_set_frozen(ssh, 0);\r
3506             if (s->dlgret == 0) {\r
3507                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
3508                                0, TRUE);\r
3509                 crStop(0);\r
3510             }\r
3511         }\r
3512     }\r
3514     switch (s->cipher_type) {\r
3515       case SSH_CIPHER_3DES:\r
3516         logevent("Using 3DES encryption");\r
3517         break;\r
3518       case SSH_CIPHER_DES:\r
3519         logevent("Using single-DES encryption");\r
3520         break;\r
3521       case SSH_CIPHER_BLOWFISH:\r
3522         logevent("Using Blowfish encryption");\r
3523         break;\r
3524     }\r
3526     send_packet(ssh, SSH1_CMSG_SESSION_KEY,\r
3527                 PKT_CHAR, s->cipher_type,\r
3528                 PKT_DATA, cookie, 8,\r
3529                 PKT_CHAR, (s->len * 8) >> 8, PKT_CHAR, (s->len * 8) & 0xFF,\r
3530                 PKT_DATA, s->rsabuf, s->len,\r
3531                 PKT_INT, ssh->v1_local_protoflags, PKT_END);\r
3533     logevent("Trying to enable encryption...");\r
3535     sfree(s->rsabuf);\r
3537     ssh->cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :\r
3538                    s->cipher_type == SSH_CIPHER_DES ? &ssh_des :\r
3539                    &ssh_3des);\r
3540     ssh->v1_cipher_ctx = ssh->cipher->make_context();\r
3541     ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key);\r
3542     logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name);\r
3544     ssh->crcda_ctx = crcda_make_context();\r
3545     logevent("Installing CRC compensation attack detector");\r
3547     if (s->servkey.modulus) {\r
3548         sfree(s->servkey.modulus);\r
3549         s->servkey.modulus = NULL;\r
3550     }\r
3551     if (s->servkey.exponent) {\r
3552         sfree(s->servkey.exponent);\r
3553         s->servkey.exponent = NULL;\r
3554     }\r
3555     if (s->hostkey.modulus) {\r
3556         sfree(s->hostkey.modulus);\r
3557         s->hostkey.modulus = NULL;\r
3558     }\r
3559     if (s->hostkey.exponent) {\r
3560         sfree(s->hostkey.exponent);\r
3561         s->hostkey.exponent = NULL;\r
3562     }\r
3563     crWaitUntil(pktin);\r
3565     if (pktin->type != SSH1_SMSG_SUCCESS) {\r
3566         bombout(("Encryption not successfully enabled"));\r
3567         crStop(0);\r
3568     }\r
3570     logevent("Successfully started encryption");\r
3572     fflush(stdout); /* FIXME eh? */\r
3573     {\r
3574         if ((ssh->username = get_remote_username(ssh->conf)) == NULL) {\r
3575             int ret; /* need not be kept over crReturn */\r
3576             s->cur_prompt = new_prompts(ssh->frontend);\r
3577             s->cur_prompt->to_server = TRUE;\r
3578             s->cur_prompt->name = dupstr("SSH login name");\r
3579             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);\r
3580             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
3581             while (ret < 0) {\r
3582                 ssh->send_ok = 1;\r
3583                 crWaitUntil(!pktin);\r
3584                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
3585                 ssh->send_ok = 0;\r
3586             }\r
3587             if (!ret) {\r
3588                 /*\r
3589                  * Failed to get a username. Terminate.\r
3590                  */\r
3591                 free_prompts(s->cur_prompt);\r
3592                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
3593                 crStop(0);\r
3594             }\r
3595             ssh->username = dupstr(s->cur_prompt->prompts[0]->result);\r
3596             free_prompts(s->cur_prompt);\r
3597         }\r
3599         send_packet(ssh, SSH1_CMSG_USER, PKT_STR, ssh->username, PKT_END);\r
3600         {\r
3601             char *userlog = dupprintf("Sent username \"%s\"", ssh->username);\r
3602             logevent(userlog);\r
3603             if (flags & FLAG_INTERACTIVE &&\r
3604                 (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {\r
3605                 c_write_str(ssh, userlog);\r
3606                 c_write_str(ssh, "\r\n");\r
3607             }\r
3608             sfree(userlog);\r
3609         }\r
3610     }\r
3612     crWaitUntil(pktin);\r
3614     if ((s->supported_auths_mask & (1 << SSH1_AUTH_RSA)) == 0) {\r
3615         /* We must not attempt PK auth. Pretend we've already tried it. */\r
3616         s->tried_publickey = s->tried_agent = 1;\r
3617     } else {\r
3618         s->tried_publickey = s->tried_agent = 0;\r
3619     }\r
3620     s->tis_auth_refused = s->ccard_auth_refused = 0;\r
3621     /*\r
3622      * Load the public half of any configured keyfile for later use.\r
3623      */\r
3624     s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
3625     if (!filename_is_null(s->keyfile)) {\r
3626         int keytype;\r
3627         logeventf(ssh, "Reading private key file \"%.150s\"",\r
3628                   filename_to_str(s->keyfile));\r
3629         keytype = key_type(s->keyfile);\r
3630         if (keytype == SSH_KEYTYPE_SSH1) {\r
3631             const char *error;\r
3632             if (rsakey_pubblob(s->keyfile,\r
3633                                &s->publickey_blob, &s->publickey_bloblen,\r
3634                                &s->publickey_comment, &error)) {\r
3635                 s->publickey_encrypted = rsakey_encrypted(s->keyfile,\r
3636                                                           NULL);\r
3637             } else {\r
3638                 char *msgbuf;\r
3639                 logeventf(ssh, "Unable to load private key (%s)", error);\r
3640                 msgbuf = dupprintf("Unable to load private key file "\r
3641                                    "\"%.150s\" (%s)\r\n",\r
3642                                    filename_to_str(s->keyfile),\r
3643                                    error);\r
3644                 c_write_str(ssh, msgbuf);\r
3645                 sfree(msgbuf);\r
3646                 s->publickey_blob = NULL;\r
3647             }\r
3648         } else {\r
3649             char *msgbuf;\r
3650             logeventf(ssh, "Unable to use this key file (%s)",\r
3651                       key_type_to_str(keytype));\r
3652             msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
3653                                " (%s)\r\n",\r
3654                                filename_to_str(s->keyfile),\r
3655                                key_type_to_str(keytype));\r
3656             c_write_str(ssh, msgbuf);\r
3657             sfree(msgbuf);\r
3658             s->publickey_blob = NULL;\r
3659         }\r
3660     } else\r
3661         s->publickey_blob = NULL;\r
3663     while (pktin->type == SSH1_SMSG_FAILURE) {\r
3664         s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;\r
3666         if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists() && !s->tried_agent) {\r
3667             /*\r
3668              * Attempt RSA authentication using Pageant.\r
3669              */\r
3670             void *r;\r
3672             s->authed = FALSE;\r
3673             s->tried_agent = 1;\r
3674             logevent("Pageant is running. Requesting keys.");\r
3676             /* Request the keys held by the agent. */\r
3677             PUT_32BIT(s->request, 1);\r
3678             s->request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;\r
3679             if (!agent_query(s->request, 5, &r, &s->responselen,\r
3680                              ssh_agent_callback, ssh)) {\r
3681                 do {\r
3682                     crReturn(0);\r
3683                     if (pktin) {\r
3684                         bombout(("Unexpected data from server while waiting"\r
3685                                  " for agent response"));\r
3686                         crStop(0);\r
3687                     }\r
3688                 } while (pktin || inlen > 0);\r
3689                 r = ssh->agent_response;\r
3690                 s->responselen = ssh->agent_response_len;\r
3691             }\r
3692             s->response = (unsigned char *) r;\r
3693             if (s->response && s->responselen >= 5 &&\r
3694                 s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {\r
3695                 s->p = s->response + 5;\r
3696                 s->nkeys = toint(GET_32BIT(s->p));\r
3697                 if (s->nkeys < 0) {\r
3698                     logeventf(ssh, "Pageant reported negative key count %d",\r
3699                               s->nkeys);\r
3700                     s->nkeys = 0;\r
3701                 }\r
3702                 s->p += 4;\r
3703                 logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys);\r
3704                 for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {\r
3705                     unsigned char *pkblob = s->p;\r
3706                     s->p += 4;\r
3707                     {\r
3708                         int n, ok = FALSE;\r
3709                         do {           /* do while (0) to make breaking easy */\r
3710                             n = ssh1_read_bignum\r
3711                                 (s->p, toint(s->responselen-(s->p-s->response)),\r
3712                                  &s->key.exponent);\r
3713                             if (n < 0)\r
3714                                 break;\r
3715                             s->p += n;\r
3716                             n = ssh1_read_bignum\r
3717                                 (s->p, toint(s->responselen-(s->p-s->response)),\r
3718                                  &s->key.modulus);\r
3719                             if (n < 0)\r
3720                                 break;\r
3721                             s->p += n;\r
3722                             if (s->responselen - (s->p-s->response) < 4)\r
3723                                 break;\r
3724                             s->commentlen = toint(GET_32BIT(s->p));\r
3725                             s->p += 4;\r
3726                             if (s->commentlen < 0 ||\r
3727                                 toint(s->responselen - (s->p-s->response)) <\r
3728                                 s->commentlen)\r
3729                                 break;\r
3730                             s->commentp = (char *)s->p;\r
3731                             s->p += s->commentlen;\r
3732                             ok = TRUE;\r
3733                         } while (0);\r
3734                         if (!ok) {\r
3735                             logevent("Pageant key list packet was truncated");\r
3736                             break;\r
3737                         }\r
3738                     }\r
3739                     if (s->publickey_blob) {\r
3740                         if (!memcmp(pkblob, s->publickey_blob,\r
3741                                     s->publickey_bloblen)) {\r
3742                             logeventf(ssh, "Pageant key #%d matches "\r
3743                                       "configured key file", s->keyi);\r
3744                             s->tried_publickey = 1;\r
3745                         } else\r
3746                             /* Skip non-configured key */\r
3747                             continue;\r
3748                     }\r
3749                     logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
3750                     send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
3751                                 PKT_BIGNUM, s->key.modulus, PKT_END);\r
3752                     crWaitUntil(pktin);\r
3753                     if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
3754                         logevent("Key refused");\r
3755                         continue;\r
3756                     }\r
3757                     logevent("Received RSA challenge");\r
3758                     if ((s->challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
3759                         bombout(("Server's RSA challenge was badly formatted"));\r
3760                         crStop(0);\r
3761                     }\r
3763                     {\r
3764                         char *agentreq, *q, *ret;\r
3765                         void *vret;\r
3766                         int len, retlen;\r
3767                         len = 1 + 4;   /* message type, bit count */\r
3768                         len += ssh1_bignum_length(s->key.exponent);\r
3769                         len += ssh1_bignum_length(s->key.modulus);\r
3770                         len += ssh1_bignum_length(s->challenge);\r
3771                         len += 16;     /* session id */\r
3772                         len += 4;      /* response format */\r
3773                         agentreq = snewn(4 + len, char);\r
3774                         PUT_32BIT(agentreq, len);\r
3775                         q = agentreq + 4;\r
3776                         *q++ = SSH1_AGENTC_RSA_CHALLENGE;\r
3777                         PUT_32BIT(q, bignum_bitcount(s->key.modulus));\r
3778                         q += 4;\r
3779                         q += ssh1_write_bignum(q, s->key.exponent);\r
3780                         q += ssh1_write_bignum(q, s->key.modulus);\r
3781                         q += ssh1_write_bignum(q, s->challenge);\r
3782                         memcpy(q, s->session_id, 16);\r
3783                         q += 16;\r
3784                         PUT_32BIT(q, 1);        /* response format */\r
3785                         if (!agent_query(agentreq, len + 4, &vret, &retlen,\r
3786                                          ssh_agent_callback, ssh)) {\r
3787                             sfree(agentreq);\r
3788                             do {\r
3789                                 crReturn(0);\r
3790                                 if (pktin) {\r
3791                                     bombout(("Unexpected data from server"\r
3792                                              " while waiting for agent"\r
3793                                              " response"));\r
3794                                     crStop(0);\r
3795                                 }\r
3796                             } while (pktin || inlen > 0);\r
3797                             vret = ssh->agent_response;\r
3798                             retlen = ssh->agent_response_len;\r
3799                         } else\r
3800                             sfree(agentreq);\r
3801                         ret = vret;\r
3802                         if (ret) {\r
3803                             if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {\r
3804                                 logevent("Sending Pageant's response");\r
3805                                 send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
3806                                             PKT_DATA, ret + 5, 16,\r
3807                                             PKT_END);\r
3808                                 sfree(ret);\r
3809                                 crWaitUntil(pktin);\r
3810                                 if (pktin->type == SSH1_SMSG_SUCCESS) {\r
3811                                     logevent\r
3812                                         ("Pageant's response accepted");\r
3813                                     if (flags & FLAG_VERBOSE) {\r
3814                                         c_write_str(ssh, "Authenticated using"\r
3815                                                     " RSA key \"");\r
3816                                         c_write(ssh, s->commentp,\r
3817                                                 s->commentlen);\r
3818                                         c_write_str(ssh, "\" from agent\r\n");\r
3819                                     }\r
3820                                     s->authed = TRUE;\r
3821                                 } else\r
3822                                     logevent\r
3823                                         ("Pageant's response not accepted");\r
3824                             } else {\r
3825                                 logevent\r
3826                                     ("Pageant failed to answer challenge");\r
3827                                 sfree(ret);\r
3828                             }\r
3829                         } else {\r
3830                             logevent("No reply received from Pageant");\r
3831                         }\r
3832                     }\r
3833                     freebn(s->key.exponent);\r
3834                     freebn(s->key.modulus);\r
3835                     freebn(s->challenge);\r
3836                     if (s->authed)\r
3837                         break;\r
3838                 }\r
3839                 sfree(s->response);\r
3840                 if (s->publickey_blob && !s->tried_publickey)\r
3841                     logevent("Configured key file not in Pageant");\r
3842             } else {\r
3843                 logevent("Failed to get reply from Pageant");\r
3844             }\r
3845             if (s->authed)\r
3846                 break;\r
3847         }\r
3848         if (s->publickey_blob && !s->tried_publickey) {\r
3849             /*\r
3850              * Try public key authentication with the specified\r
3851              * key file.\r
3852              */\r
3853             int got_passphrase; /* need not be kept over crReturn */\r
3854             if (flags & FLAG_VERBOSE)\r
3855                 c_write_str(ssh, "Trying public key authentication.\r\n");\r
3856             s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
3857             logeventf(ssh, "Trying public key \"%s\"",\r
3858                       filename_to_str(s->keyfile));\r
3859             s->tried_publickey = 1;\r
3860             got_passphrase = FALSE;\r
3861             while (!got_passphrase) {\r
3862                 /*\r
3863                  * Get a passphrase, if necessary.\r
3864                  */\r
3865                 char *passphrase = NULL;    /* only written after crReturn */\r
3866                 const char *error;\r
3867                 if (!s->publickey_encrypted) {\r
3868                     if (flags & FLAG_VERBOSE)\r
3869                         c_write_str(ssh, "No passphrase required.\r\n");\r
3870                     passphrase = NULL;\r
3871                 } else {\r
3872                     int ret; /* need not be kept over crReturn */\r
3873                     s->cur_prompt = new_prompts(ssh->frontend);\r
3874                     s->cur_prompt->to_server = FALSE;\r
3875                     s->cur_prompt->name = dupstr("SSH key passphrase");\r
3876                     add_prompt(s->cur_prompt,\r
3877                                dupprintf("Passphrase for key \"%.100s\": ",\r
3878                                          s->publickey_comment), FALSE);\r
3879                     ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
3880                     while (ret < 0) {\r
3881                         ssh->send_ok = 1;\r
3882                         crWaitUntil(!pktin);\r
3883                         ret = get_userpass_input(s->cur_prompt, in, inlen);\r
3884                         ssh->send_ok = 0;\r
3885                     }\r
3886                     if (!ret) {\r
3887                         /* Failed to get a passphrase. Terminate. */\r
3888                         free_prompts(s->cur_prompt);\r
3889                         ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
3890                                        0, TRUE);\r
3891                         crStop(0);\r
3892                     }\r
3893                     passphrase = dupstr(s->cur_prompt->prompts[0]->result);\r
3894                     free_prompts(s->cur_prompt);\r
3895                 }\r
3896                 /*\r
3897                  * Try decrypting key with passphrase.\r
3898                  */\r
3899                 s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
3900                 ret = loadrsakey(s->keyfile, &s->key, passphrase,\r
3901                                  &error);\r
3902                 if (passphrase) {\r
3903                     smemclr(passphrase, strlen(passphrase));\r
3904                     sfree(passphrase);\r
3905                 }\r
3906                 if (ret == 1) {\r
3907                     /* Correct passphrase. */\r
3908                     got_passphrase = TRUE;\r
3909                 } else if (ret == 0) {\r
3910                     c_write_str(ssh, "Couldn't load private key from ");\r
3911                     c_write_str(ssh, filename_to_str(s->keyfile));\r
3912                     c_write_str(ssh, " (");\r
3913                     c_write_str(ssh, error);\r
3914                     c_write_str(ssh, ").\r\n");\r
3915                     got_passphrase = FALSE;\r
3916                     break;             /* go and try something else */\r
3917                 } else if (ret == -1) {\r
3918                     c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */\r
3919                     got_passphrase = FALSE;\r
3920                     /* and try again */\r
3921                 } else {\r
3922                     assert(0 && "unexpected return from loadrsakey()");\r
3923                     got_passphrase = FALSE;   /* placate optimisers */\r
3924                 }\r
3925             }\r
3927             if (got_passphrase) {\r
3929                 /*\r
3930                  * Send a public key attempt.\r
3931                  */\r
3932                 send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
3933                             PKT_BIGNUM, s->key.modulus, PKT_END);\r
3935                 crWaitUntil(pktin);\r
3936                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
3937                     c_write_str(ssh, "Server refused our public key.\r\n");\r
3938                     continue;          /* go and try something else */\r
3939                 }\r
3940                 if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
3941                     bombout(("Bizarre response to offer of public key"));\r
3942                     crStop(0);\r
3943                 }\r
3945                 {\r
3946                     int i;\r
3947                     unsigned char buffer[32];\r
3948                     Bignum challenge, response;\r
3950                     if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
3951                         bombout(("Server's RSA challenge was badly formatted"));\r
3952                         crStop(0);\r
3953                     }\r
3954                     response = rsadecrypt(challenge, &s->key);\r
3955                     freebn(s->key.private_exponent);/* burn the evidence */\r
3957                     for (i = 0; i < 32; i++) {\r
3958                         buffer[i] = bignum_byte(response, 31 - i);\r
3959                     }\r
3961                     MD5Init(&md5c);\r
3962                     MD5Update(&md5c, buffer, 32);\r
3963                     MD5Update(&md5c, s->session_id, 16);\r
3964                     MD5Final(buffer, &md5c);\r
3966                     send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
3967                                 PKT_DATA, buffer, 16, PKT_END);\r
3969                     freebn(challenge);\r
3970                     freebn(response);\r
3971                 }\r
3973                 crWaitUntil(pktin);\r
3974                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
3975                     if (flags & FLAG_VERBOSE)\r
3976                         c_write_str(ssh, "Failed to authenticate with"\r
3977                                     " our public key.\r\n");\r
3978                     continue;          /* go and try something else */\r
3979                 } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
3980                     bombout(("Bizarre response to RSA authentication response"));\r
3981                     crStop(0);\r
3982                 }\r
3984                 break;                 /* we're through! */\r
3985             }\r
3987         }\r
3989         /*\r
3990          * Otherwise, try various forms of password-like authentication.\r
3991          */\r
3992         s->cur_prompt = new_prompts(ssh->frontend);\r
3994         if (conf_get_int(ssh->conf, CONF_try_tis_auth) &&\r
3995             (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&\r
3996             !s->tis_auth_refused) {\r
3997             s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;\r
3998             logevent("Requested TIS authentication");\r
3999             send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END);\r
4000             crWaitUntil(pktin);\r
4001             if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {\r
4002                 logevent("TIS authentication declined");\r
4003                 if (flags & FLAG_INTERACTIVE)\r
4004                     c_write_str(ssh, "TIS authentication refused.\r\n");\r
4005                 s->tis_auth_refused = 1;\r
4006                 continue;\r
4007             } else {\r
4008                 char *challenge;\r
4009                 int challengelen;\r
4010                 char *instr_suf, *prompt;\r
4012                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
4013                 if (!challenge) {\r
4014                     bombout(("TIS challenge packet was badly formed"));\r
4015                     crStop(0);\r
4016                 }\r
4017                 logevent("Received TIS challenge");\r
4018                 s->cur_prompt->to_server = TRUE;\r
4019                 s->cur_prompt->name = dupstr("SSH TIS authentication");\r
4020                 /* Prompt heuristic comes from OpenSSH */\r
4021                 if (memchr(challenge, '\n', challengelen)) {\r
4022                     instr_suf = dupstr("");\r
4023                     prompt = dupprintf("%.*s", challengelen, challenge);\r
4024                 } else {\r
4025                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
4026                     prompt = dupstr("Response: ");\r
4027                 }\r
4028                 s->cur_prompt->instruction =\r
4029                     dupprintf("Using TIS authentication.%s%s",\r
4030                               (*instr_suf) ? "\n" : "",\r
4031                               instr_suf);\r
4032                 s->cur_prompt->instr_reqd = TRUE;\r
4033                 add_prompt(s->cur_prompt, prompt, FALSE);\r
4034                 sfree(instr_suf);\r
4035             }\r
4036         }\r
4037         if (conf_get_int(ssh->conf, CONF_try_tis_auth) &&\r
4038             (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&\r
4039             !s->ccard_auth_refused) {\r
4040             s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;\r
4041             logevent("Requested CryptoCard authentication");\r
4042             send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END);\r
4043             crWaitUntil(pktin);\r
4044             if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {\r
4045                 logevent("CryptoCard authentication declined");\r
4046                 c_write_str(ssh, "CryptoCard authentication refused.\r\n");\r
4047                 s->ccard_auth_refused = 1;\r
4048                 continue;\r
4049             } else {\r
4050                 char *challenge;\r
4051                 int challengelen;\r
4052                 char *instr_suf, *prompt;\r
4054                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
4055                 if (!challenge) {\r
4056                     bombout(("CryptoCard challenge packet was badly formed"));\r
4057                     crStop(0);\r
4058                 }\r
4059                 logevent("Received CryptoCard challenge");\r
4060                 s->cur_prompt->to_server = TRUE;\r
4061                 s->cur_prompt->name = dupstr("SSH CryptoCard authentication");\r
4062                 s->cur_prompt->name_reqd = FALSE;\r
4063                 /* Prompt heuristic comes from OpenSSH */\r
4064                 if (memchr(challenge, '\n', challengelen)) {\r
4065                     instr_suf = dupstr("");\r
4066                     prompt = dupprintf("%.*s", challengelen, challenge);\r
4067                 } else {\r
4068                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
4069                     prompt = dupstr("Response: ");\r
4070                 }\r
4071                 s->cur_prompt->instruction =\r
4072                     dupprintf("Using CryptoCard authentication.%s%s",\r
4073                               (*instr_suf) ? "\n" : "",\r
4074                               instr_suf);\r
4075                 s->cur_prompt->instr_reqd = TRUE;\r
4076                 add_prompt(s->cur_prompt, prompt, FALSE);\r
4077                 sfree(instr_suf);\r
4078             }\r
4079         }\r
4080         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
4081             if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) {\r
4082                 bombout(("No supported authentication methods available"));\r
4083                 crStop(0);\r
4084             }\r
4085             s->cur_prompt->to_server = TRUE;\r
4086             s->cur_prompt->name = dupstr("SSH password");\r
4087             add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",\r
4088                                                 ssh->username, ssh->savedhost),\r
4089                        FALSE);\r
4090         }\r
4092         /*\r
4093          * Show password prompt, having first obtained it via a TIS\r
4094          * or CryptoCard exchange if we're doing TIS or CryptoCard\r
4095          * authentication.\r
4096          */\r
4097         {\r
4098             int ret; /* need not be kept over crReturn */\r
4099             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
4100             while (ret < 0) {\r
4101                 ssh->send_ok = 1;\r
4102                 crWaitUntil(!pktin);\r
4103                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
4104                 ssh->send_ok = 0;\r
4105             }\r
4106             if (!ret) {\r
4107                 /*\r
4108                  * Failed to get a password (for example\r
4109                  * because one was supplied on the command line\r
4110                  * which has already failed to work). Terminate.\r
4111                  */\r
4112                 free_prompts(s->cur_prompt);\r
4113                 ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE);\r
4114                 crStop(0);\r
4115             }\r
4116         }\r
4118         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
4119             /*\r
4120              * Defence against traffic analysis: we send a\r
4121              * whole bunch of packets containing strings of\r
4122              * different lengths. One of these strings is the\r
4123              * password, in a SSH1_CMSG_AUTH_PASSWORD packet.\r
4124              * The others are all random data in\r
4125              * SSH1_MSG_IGNORE packets. This way a passive\r
4126              * listener can't tell which is the password, and\r
4127              * hence can't deduce the password length.\r
4128              * \r
4129              * Anybody with a password length greater than 16\r
4130              * bytes is going to have enough entropy in their\r
4131              * password that a listener won't find it _that_\r
4132              * much help to know how long it is. So what we'll\r
4133              * do is:\r
4134              * \r
4135              *  - if password length < 16, we send 15 packets\r
4136              *    containing string lengths 1 through 15\r
4137              * \r
4138              *  - otherwise, we let N be the nearest multiple\r
4139              *    of 8 below the password length, and send 8\r
4140              *    packets containing string lengths N through\r
4141              *    N+7. This won't obscure the order of\r
4142              *    magnitude of the password length, but it will\r
4143              *    introduce a bit of extra uncertainty.\r
4144              * \r
4145              * A few servers can't deal with SSH1_MSG_IGNORE, at\r
4146              * least in this context. For these servers, we need\r
4147              * an alternative defence. We make use of the fact\r
4148              * that the password is interpreted as a C string:\r
4149              * so we can append a NUL, then some random data.\r
4150              * \r
4151              * A few servers can deal with neither SSH1_MSG_IGNORE\r
4152              * here _nor_ a padded password string.\r
4153              * For these servers we are left with no defences\r
4154              * against password length sniffing.\r
4155              */\r
4156             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) &&\r
4157                 !(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
4158                 /*\r
4159                  * The server can deal with SSH1_MSG_IGNORE, so\r
4160                  * we can use the primary defence.\r
4161                  */\r
4162                 int bottom, top, pwlen, i;\r
4163                 char *randomstr;\r
4165                 pwlen = strlen(s->cur_prompt->prompts[0]->result);\r
4166                 if (pwlen < 16) {\r
4167                     bottom = 0;    /* zero length passwords are OK! :-) */\r
4168                     top = 15;\r
4169                 } else {\r
4170                     bottom = pwlen & ~7;\r
4171                     top = bottom + 7;\r
4172                 }\r
4174                 assert(pwlen >= bottom && pwlen <= top);\r
4176                 randomstr = snewn(top + 1, char);\r
4178                 for (i = bottom; i <= top; i++) {\r
4179                     if (i == pwlen) {\r
4180                         defer_packet(ssh, s->pwpkt_type,\r
4181                                      PKTT_PASSWORD, PKT_STR,\r
4182                                      s->cur_prompt->prompts[0]->result,\r
4183                                      PKTT_OTHER, PKT_END);\r
4184                     } else {\r
4185                         for (j = 0; j < i; j++) {\r
4186                             do {\r
4187                                 randomstr[j] = random_byte();\r
4188                             } while (randomstr[j] == '\0');\r
4189                         }\r
4190                         randomstr[i] = '\0';\r
4191                         defer_packet(ssh, SSH1_MSG_IGNORE,\r
4192                                      PKT_STR, randomstr, PKT_END);\r
4193                     }\r
4194                 }\r
4195                 logevent("Sending password with camouflage packets");\r
4196                 ssh_pkt_defersend(ssh);\r
4197                 sfree(randomstr);\r
4198             } \r
4199             else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
4200                 /*\r
4201                  * The server can't deal with SSH1_MSG_IGNORE\r
4202                  * but can deal with padded passwords, so we\r
4203                  * can use the secondary defence.\r
4204                  */\r
4205                 char string[64];\r
4206                 char *ss;\r
4207                 int len;\r
4209                 len = strlen(s->cur_prompt->prompts[0]->result);\r
4210                 if (len < sizeof(string)) {\r
4211                     ss = string;\r
4212                     strcpy(string, s->cur_prompt->prompts[0]->result);\r
4213                     len++;             /* cover the zero byte */\r
4214                     while (len < sizeof(string)) {\r
4215                         string[len++] = (char) random_byte();\r
4216                     }\r
4217                 } else {\r
4218                     ss = s->cur_prompt->prompts[0]->result;\r
4219                 }\r
4220                 logevent("Sending length-padded password");\r
4221                 send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,\r
4222                             PKT_INT, len, PKT_DATA, ss, len,\r
4223                             PKTT_OTHER, PKT_END);\r
4224             } else {\r
4225                 /*\r
4226                  * The server is believed unable to cope with\r
4227                  * any of our password camouflage methods.\r
4228                  */\r
4229                 int len;\r
4230                 len = strlen(s->cur_prompt->prompts[0]->result);\r
4231                 logevent("Sending unpadded password");\r
4232                 send_packet(ssh, s->pwpkt_type,\r
4233                             PKTT_PASSWORD, PKT_INT, len,\r
4234                             PKT_DATA, s->cur_prompt->prompts[0]->result, len,\r
4235                             PKTT_OTHER, PKT_END);\r
4236             }\r
4237         } else {\r
4238             send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,\r
4239                         PKT_STR, s->cur_prompt->prompts[0]->result,\r
4240                         PKTT_OTHER, PKT_END);\r
4241         }\r
4242         logevent("Sent password");\r
4243         free_prompts(s->cur_prompt);\r
4244         crWaitUntil(pktin);\r
4245         if (pktin->type == SSH1_SMSG_FAILURE) {\r
4246             if (flags & FLAG_VERBOSE)\r
4247                 c_write_str(ssh, "Access denied\r\n");\r
4248             logevent("Authentication refused");\r
4249         } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
4250             bombout(("Strange packet received, type %d", pktin->type));\r
4251             crStop(0);\r
4252         }\r
4253     }\r
4255     /* Clear up */\r
4256     if (s->publickey_blob) {\r
4257         sfree(s->publickey_blob);\r
4258         sfree(s->publickey_comment);\r
4259     }\r
4261     logevent("Authentication successful");\r
4263     crFinish(1);\r
4266 static void ssh_channel_try_eof(struct ssh_channel *c)\r
4268     Ssh ssh = c->ssh;\r
4269     assert(c->pending_eof);          /* precondition for calling us */\r
4270     if (c->halfopen)\r
4271         return;                 /* can't close: not even opened yet */\r
4272     if (ssh->version == 2 && bufchain_size(&c->v.v2.outbuffer) > 0)\r
4273         return;              /* can't send EOF: pending outgoing data */\r
4275     c->pending_eof = FALSE;            /* we're about to send it */\r
4276     if (ssh->version == 1) {\r
4277         send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,\r
4278                     PKT_END);\r
4279         c->closes |= CLOSES_SENT_EOF;\r
4280     } else {\r
4281         struct Packet *pktout;\r
4282         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);\r
4283         ssh2_pkt_adduint32(pktout, c->remoteid);\r
4284         ssh2_pkt_send(ssh, pktout);\r
4285         c->closes |= CLOSES_SENT_EOF;\r
4286         ssh2_channel_check_close(c);\r
4287     }\r
4290 void sshfwd_write_eof(struct ssh_channel *c)\r
4292     Ssh ssh = c->ssh;\r
4294     if (ssh->state == SSH_STATE_CLOSED)\r
4295         return;\r
4297     if (c->closes & CLOSES_SENT_EOF)\r
4298         return;\r
4300     c->pending_eof = TRUE;\r
4301     ssh_channel_try_eof(c);\r
4304 void sshfwd_unclean_close(struct ssh_channel *c)\r
4306     Ssh ssh = c->ssh;\r
4308     if (ssh->state == SSH_STATE_CLOSED)\r
4309         return;\r
4311     switch (c->type) {\r
4312       case CHAN_X11:\r
4313         x11_close(c->u.x11.s);\r
4314         logevent("Forwarded X11 connection terminated due to local error");\r
4315         break;\r
4316       case CHAN_SOCKDATA:\r
4317       case CHAN_SOCKDATA_DORMANT:\r
4318         pfd_close(c->u.pfd.s);\r
4319         logevent("Forwarded port closed due to local error");\r
4320         break;\r
4321     }\r
4322     c->type = CHAN_ZOMBIE;\r
4324     ssh2_channel_check_close(c);\r
4327 int sshfwd_write(struct ssh_channel *c, char *buf, int len)\r
4329     Ssh ssh = c->ssh;\r
4331     if (ssh->state == SSH_STATE_CLOSED)\r
4332         return 0;\r
4334     if (ssh->version == 1) {\r
4335         send_packet(ssh, SSH1_MSG_CHANNEL_DATA,\r
4336                     PKT_INT, c->remoteid,\r
4337                     PKT_INT, len, PKTT_DATA, PKT_DATA, buf, len,\r
4338                     PKTT_OTHER, PKT_END);\r
4339         /*\r
4340          * In SSH-1 we can return 0 here - implying that forwarded\r
4341          * connections are never individually throttled - because\r
4342          * the only circumstance that can cause throttling will be\r
4343          * the whole SSH connection backing up, in which case\r
4344          * _everything_ will be throttled as a whole.\r
4345          */\r
4346         return 0;\r
4347     } else {\r
4348         ssh2_add_channel_data(c, buf, len);\r
4349         return ssh2_try_send(c);\r
4350     }\r
4353 void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)\r
4355     Ssh ssh = c->ssh;\r
4356     int buflimit;\r
4358     if (ssh->state == SSH_STATE_CLOSED)\r
4359         return;\r
4361     if (ssh->version == 1) {\r
4362         buflimit = SSH1_BUFFER_LIMIT;\r
4363     } else {\r
4364         buflimit = c->v.v2.locmaxwin;\r
4365         ssh2_set_window(c, bufsize < buflimit ? buflimit - bufsize : 0);\r
4366     }\r
4367     if (c->throttling_conn && bufsize <= buflimit) {\r
4368         c->throttling_conn = 0;\r
4369         ssh_throttle_conn(ssh, -1);\r
4370     }\r
4373 static void ssh_queueing_handler(Ssh ssh, struct Packet *pktin)\r
4375     struct queued_handler *qh = ssh->qhead;\r
4377     assert(qh != NULL);\r
4379     assert(pktin->type == qh->msg1 || pktin->type == qh->msg2);\r
4381     if (qh->msg1 > 0) {\r
4382         assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler);\r
4383         ssh->packet_dispatch[qh->msg1] = ssh->q_saved_handler1;\r
4384     }\r
4385     if (qh->msg2 > 0) {\r
4386         assert(ssh->packet_dispatch[qh->msg2] == ssh_queueing_handler);\r
4387         ssh->packet_dispatch[qh->msg2] = ssh->q_saved_handler2;\r
4388     }\r
4390     if (qh->next) {\r
4391         ssh->qhead = qh->next;\r
4393         if (ssh->qhead->msg1 > 0) {\r
4394             ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1];\r
4395             ssh->packet_dispatch[ssh->qhead->msg1] = ssh_queueing_handler;\r
4396         }\r
4397         if (ssh->qhead->msg2 > 0) {\r
4398             ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2];\r
4399             ssh->packet_dispatch[ssh->qhead->msg2] = ssh_queueing_handler;\r
4400         }\r
4401     } else {\r
4402         ssh->qhead = ssh->qtail = NULL;\r
4403     }\r
4405     qh->handler(ssh, pktin, qh->ctx);\r
4407     sfree(qh);\r
4410 static void ssh_queue_handler(Ssh ssh, int msg1, int msg2,\r
4411                               chandler_fn_t handler, void *ctx)\r
4413     struct queued_handler *qh;\r
4415     qh = snew(struct queued_handler);\r
4416     qh->msg1 = msg1;\r
4417     qh->msg2 = msg2;\r
4418     qh->handler = handler;\r
4419     qh->ctx = ctx;\r
4420     qh->next = NULL;\r
4422     if (ssh->qtail == NULL) {\r
4423         ssh->qhead = qh;\r
4425         if (qh->msg1 > 0) {\r
4426             ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1];\r
4427             ssh->packet_dispatch[qh->msg1] = ssh_queueing_handler;\r
4428         }\r
4429         if (qh->msg2 > 0) {\r
4430             ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2];\r
4431             ssh->packet_dispatch[qh->msg2] = ssh_queueing_handler;\r
4432         }\r
4433     } else {\r
4434         ssh->qtail->next = qh;\r
4435     }\r
4436     ssh->qtail = qh;\r
4439 static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx)\r
4441     struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx;\r
4443     if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS :\r
4444                         SSH2_MSG_REQUEST_SUCCESS)) {\r
4445         logeventf(ssh, "Remote port forwarding from %s enabled",\r
4446                   pf->sportdesc);\r
4447     } else {\r
4448         logeventf(ssh, "Remote port forwarding from %s refused",\r
4449                   pf->sportdesc);\r
4451         rpf = del234(ssh->rportfwds, pf);\r
4452         assert(rpf == pf);\r
4453         pf->pfrec->remote = NULL;\r
4454         free_rportfwd(pf);\r
4455     }\r
4458 static void ssh_setup_portfwd(Ssh ssh, Conf *conf)\r
4460     struct ssh_portfwd *epf;\r
4461     int i;\r
4462     char *key, *val;\r
4464     if (!ssh->portfwds) {\r
4465         ssh->portfwds = newtree234(ssh_portcmp);\r
4466     } else {\r
4467         /*\r
4468          * Go through the existing port forwardings and tag them\r
4469          * with status==DESTROY. Any that we want to keep will be\r
4470          * re-enabled (status==KEEP) as we go through the\r
4471          * configuration and find out which bits are the same as\r
4472          * they were before.\r
4473          */\r
4474         struct ssh_portfwd *epf;\r
4475         int i;\r
4476         for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4477             epf->status = DESTROY;\r
4478     }\r
4480     for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);\r
4481          val != NULL;\r
4482          val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {\r
4483         char *kp, *kp2, *vp, *vp2;\r
4484         char address_family, type;\r
4485         int sport,dport,sserv,dserv;\r
4486         char *sports, *dports, *saddr, *host;\r
4488         kp = key;\r
4490         address_family = 'A';\r
4491         type = 'L';\r
4492         if (*kp == 'A' || *kp == '4' || *kp == '6')\r
4493             address_family = *kp++;\r
4494         if (*kp == 'L' || *kp == 'R')\r
4495             type = *kp++;\r
4497         if ((kp2 = strchr(kp, ':')) != NULL) {\r
4498             /*\r
4499              * There's a colon in the middle of the source port\r
4500              * string, which means that the part before it is\r
4501              * actually a source address.\r
4502              */\r
4503             saddr = dupprintf("%.*s", (int)(kp2 - kp), kp);\r
4504             sports = kp2+1;\r
4505         } else {\r
4506             saddr = NULL;\r
4507             sports = kp;\r
4508         }\r
4509         sport = atoi(sports);\r
4510         sserv = 0;\r
4511         if (sport == 0) {\r
4512             sserv = 1;\r
4513             sport = net_service_lookup(sports);\r
4514             if (!sport) {\r
4515                 logeventf(ssh, "Service lookup failed for source"\r
4516                           " port \"%s\"", sports);\r
4517             }\r
4518         }\r
4520         if (type == 'L' && !strcmp(val, "D")) {\r
4521             /* dynamic forwarding */\r
4522             host = NULL;\r
4523             dports = NULL;\r
4524             dport = -1;\r
4525             dserv = 0;\r
4526             type = 'D';\r
4527         } else {\r
4528             /* ordinary forwarding */\r
4529             vp = val;\r
4530             vp2 = vp + strcspn(vp, ":");\r
4531             host = dupprintf("%.*s", (int)(vp2 - vp), vp);\r
4532             if (vp2)\r
4533                 vp2++;\r
4534             dports = vp2;\r
4535             dport = atoi(dports);\r
4536             dserv = 0;\r
4537             if (dport == 0) {\r
4538                 dserv = 1;\r
4539                 dport = net_service_lookup(dports);\r
4540                 if (!dport) {\r
4541                     logeventf(ssh, "Service lookup failed for destination"\r
4542                               " port \"%s\"", dports);\r
4543                 }\r
4544             }\r
4545         }\r
4547         if (sport && dport) {\r
4548             /* Set up a description of the source port. */\r
4549             struct ssh_portfwd *pfrec, *epfrec;\r
4551             pfrec = snew(struct ssh_portfwd);\r
4552             pfrec->type = type;\r
4553             pfrec->saddr = saddr;\r
4554             pfrec->sserv = sserv ? dupstr(sports) : NULL;\r
4555             pfrec->sport = sport;\r
4556             pfrec->daddr = host;\r
4557             pfrec->dserv = dserv ? dupstr(dports) : NULL;\r
4558             pfrec->dport = dport;\r
4559             pfrec->local = NULL;\r
4560             pfrec->remote = NULL;\r
4561             pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :\r
4562                                     address_family == '6' ? ADDRTYPE_IPV6 :\r
4563                                     ADDRTYPE_UNSPEC);\r
4565             epfrec = add234(ssh->portfwds, pfrec);\r
4566             if (epfrec != pfrec) {\r
4567                 if (epfrec->status == DESTROY) {\r
4568                     /*\r
4569                      * We already have a port forwarding up and running\r
4570                      * with precisely these parameters. Hence, no need\r
4571                      * to do anything; simply re-tag the existing one\r
4572                      * as KEEP.\r
4573                      */\r
4574                     epfrec->status = KEEP;\r
4575                 }\r
4576                 /*\r
4577                  * Anything else indicates that there was a duplicate\r
4578                  * in our input, which we'll silently ignore.\r
4579                  */\r
4580                 free_portfwd(pfrec);\r
4581             } else {\r
4582                 pfrec->status = CREATE;\r
4583             }\r
4584         } else {\r
4585             sfree(saddr);\r
4586             sfree(host);\r
4587         }\r
4588     }\r
4590     /*\r
4591      * Now go through and destroy any port forwardings which were\r
4592      * not re-enabled.\r
4593      */\r
4594     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4595         if (epf->status == DESTROY) {\r
4596             char *message;\r
4598             message = dupprintf("%s port forwarding from %s%s%d",\r
4599                                 epf->type == 'L' ? "local" :\r
4600                                 epf->type == 'R' ? "remote" : "dynamic",\r
4601                                 epf->saddr ? epf->saddr : "",\r
4602                                 epf->saddr ? ":" : "",\r
4603                                 epf->sport);\r
4605             if (epf->type != 'D') {\r
4606                 char *msg2 = dupprintf("%s to %s:%d", message,\r
4607                                        epf->daddr, epf->dport);\r
4608                 sfree(message);\r
4609                 message = msg2;\r
4610             }\r
4612             logeventf(ssh, "Cancelling %s", message);\r
4613             sfree(message);\r
4615             /* epf->remote or epf->local may be NULL if setting up a\r
4616              * forwarding failed. */\r
4617             if (epf->remote) {\r
4618                 struct ssh_rportfwd *rpf = epf->remote;\r
4619                 struct Packet *pktout;\r
4621                 /*\r
4622                  * Cancel the port forwarding at the server\r
4623                  * end.\r
4624                  */\r
4625                 if (ssh->version == 1) {\r
4626                     /*\r
4627                      * We cannot cancel listening ports on the\r
4628                      * server side in SSH-1! There's no message\r
4629                      * to support it. Instead, we simply remove\r
4630                      * the rportfwd record from the local end\r
4631                      * so that any connections the server tries\r
4632                      * to make on it are rejected.\r
4633                      */\r
4634                 } else {\r
4635                     pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
4636                     ssh2_pkt_addstring(pktout, "cancel-tcpip-forward");\r
4637                     ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */\r
4638                     if (epf->saddr) {\r
4639                         ssh2_pkt_addstring(pktout, epf->saddr);\r
4640                     } else if (conf_get_int(conf, CONF_rport_acceptall)) {\r
4641                         /* XXX: rport_acceptall may not represent\r
4642                          * what was used to open the original connection,\r
4643                          * since it's reconfigurable. */\r
4644                         ssh2_pkt_addstring(pktout, "");\r
4645                     } else {\r
4646                         ssh2_pkt_addstring(pktout, "localhost");\r
4647                     }\r
4648                     ssh2_pkt_adduint32(pktout, epf->sport);\r
4649                     ssh2_pkt_send(ssh, pktout);\r
4650                 }\r
4652                 del234(ssh->rportfwds, rpf);\r
4653                 free_rportfwd(rpf);\r
4654             } else if (epf->local) {\r
4655                 pfd_terminate(epf->local);\r
4656             }\r
4658             delpos234(ssh->portfwds, i);\r
4659             free_portfwd(epf);\r
4660             i--;                       /* so we don't skip one in the list */\r
4661         }\r
4663     /*\r
4664      * And finally, set up any new port forwardings (status==CREATE).\r
4665      */\r
4666     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4667         if (epf->status == CREATE) {\r
4668             char *sportdesc, *dportdesc;\r
4669             sportdesc = dupprintf("%s%s%s%s%d%s",\r
4670                                   epf->saddr ? epf->saddr : "",\r
4671                                   epf->saddr ? ":" : "",\r
4672                                   epf->sserv ? epf->sserv : "",\r
4673                                   epf->sserv ? "(" : "",\r
4674                                   epf->sport,\r
4675                                   epf->sserv ? ")" : "");\r
4676             if (epf->type == 'D') {\r
4677                 dportdesc = NULL;\r
4678             } else {\r
4679                 dportdesc = dupprintf("%s:%s%s%d%s",\r
4680                                       epf->daddr,\r
4681                                       epf->dserv ? epf->dserv : "",\r
4682                                       epf->dserv ? "(" : "",\r
4683                                       epf->dport,\r
4684                                       epf->dserv ? ")" : "");\r
4685             }\r
4687             if (epf->type == 'L') {\r
4688                 const char *err = pfd_addforward(epf->daddr, epf->dport,\r
4689                                                  epf->saddr, epf->sport,\r
4690                                                  ssh, conf,\r
4691                                                  &epf->local,\r
4692                                                  epf->addressfamily);\r
4694                 logeventf(ssh, "Local %sport %s forwarding to %s%s%s",\r
4695                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
4696                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
4697                           sportdesc, dportdesc,\r
4698                           err ? " failed: " : "", err ? err : "");\r
4699             } else if (epf->type == 'D') {\r
4700                 const char *err = pfd_addforward(NULL, -1,\r
4701                                                  epf->saddr, epf->sport,\r
4702                                                  ssh, conf,\r
4703                                                  &epf->local,\r
4704                                                  epf->addressfamily);\r
4706                 logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",\r
4707                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
4708                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
4709                           sportdesc,\r
4710                           err ? " failed: " : "", err ? err : "");\r
4711             } else {\r
4712                 struct ssh_rportfwd *pf;\r
4714                 /*\r
4715                  * Ensure the remote port forwardings tree exists.\r
4716                  */\r
4717                 if (!ssh->rportfwds) {\r
4718                     if (ssh->version == 1)\r
4719                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);\r
4720                     else\r
4721                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);\r
4722                 }\r
4724                 pf = snew(struct ssh_rportfwd);\r
4725                 strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1);\r
4726                 pf->dhost[lenof(pf->dhost)-1] = '\0';\r
4727                 pf->dport = epf->dport;\r
4728                 pf->sport = epf->sport;\r
4729                 if (add234(ssh->rportfwds, pf) != pf) {\r
4730                     logeventf(ssh, "Duplicate remote port forwarding to %s:%d",\r
4731                               epf->daddr, epf->dport);\r
4732                     sfree(pf);\r
4733                 } else {\r
4734                     logeventf(ssh, "Requesting remote port %s"\r
4735                               " forward to %s", sportdesc, dportdesc);\r
4737                     pf->sportdesc = sportdesc;\r
4738                     sportdesc = NULL;\r
4739                     epf->remote = pf;\r
4740                     pf->pfrec = epf;\r
4742                     if (ssh->version == 1) {\r
4743                         send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST,\r
4744                                     PKT_INT, epf->sport,\r
4745                                     PKT_STR, epf->daddr,\r
4746                                     PKT_INT, epf->dport,\r
4747                                     PKT_END);\r
4748                         ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,\r
4749                                           SSH1_SMSG_FAILURE,\r
4750                                           ssh_rportfwd_succfail, pf);\r
4751                     } else {\r
4752                         struct Packet *pktout;\r
4753                         pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
4754                         ssh2_pkt_addstring(pktout, "tcpip-forward");\r
4755                         ssh2_pkt_addbool(pktout, 1);/* want reply */\r
4756                         if (epf->saddr) {\r
4757                             ssh2_pkt_addstring(pktout, epf->saddr);\r
4758                         } else if (conf_get_int(conf, CONF_rport_acceptall)) {\r
4759                             ssh2_pkt_addstring(pktout, "");\r
4760                         } else {\r
4761                             ssh2_pkt_addstring(pktout, "localhost");\r
4762                         }\r
4763                         ssh2_pkt_adduint32(pktout, epf->sport);\r
4764                         ssh2_pkt_send(ssh, pktout);\r
4766                         ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,\r
4767                                           SSH2_MSG_REQUEST_FAILURE,\r
4768                                           ssh_rportfwd_succfail, pf);\r
4769                     }\r
4770                 }\r
4771             }\r
4772             sfree(sportdesc);\r
4773             sfree(dportdesc);\r
4774         }\r
4777 static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin)\r
4779     char *string;\r
4780     int stringlen, bufsize;\r
4782     ssh_pkt_getstring(pktin, &string, &stringlen);\r
4783     if (string == NULL) {\r
4784         bombout(("Incoming terminal data packet was badly formed"));\r
4785         return;\r
4786     }\r
4788     bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA,\r
4789                            string, stringlen);\r
4790     if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {\r
4791         ssh->v1_stdout_throttling = 1;\r
4792         ssh_throttle_conn(ssh, +1);\r
4793     }\r
4796 static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)\r
4798     /* Remote side is trying to open a channel to talk to our\r
4799      * X-Server. Give them back a local channel number. */\r
4800     struct ssh_channel *c;\r
4801     int remoteid = ssh_pkt_getuint32(pktin);\r
4803     logevent("Received X11 connect request");\r
4804     /* Refuse if X11 forwarding is disabled. */\r
4805     if (!ssh->X11_fwd_enabled) {\r
4806         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4807                     PKT_INT, remoteid, PKT_END);\r
4808         logevent("Rejected X11 connect request");\r
4809     } else {\r
4810         c = snew(struct ssh_channel);\r
4811         c->ssh = ssh;\r
4813         if (x11_init(&c->u.x11.s, ssh->x11disp, c,\r
4814                      NULL, -1, ssh->conf) != NULL) {\r
4815             logevent("Opening X11 forward connection failed");\r
4816             sfree(c);\r
4817             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4818                         PKT_INT, remoteid, PKT_END);\r
4819         } else {\r
4820             logevent\r
4821                 ("Opening X11 forward connection succeeded");\r
4822             c->remoteid = remoteid;\r
4823             c->halfopen = FALSE;\r
4824             c->localid = alloc_channel_id(ssh);\r
4825             c->closes = 0;\r
4826             c->pending_eof = FALSE;\r
4827             c->throttling_conn = 0;\r
4828             c->type = CHAN_X11; /* identify channel type */\r
4829             add234(ssh->channels, c);\r
4830             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4831                         PKT_INT, c->remoteid, PKT_INT,\r
4832                         c->localid, PKT_END);\r
4833             logevent("Opened X11 forward channel");\r
4834         }\r
4835     }\r
4838 static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)\r
4840     /* Remote side is trying to open a channel to talk to our\r
4841      * agent. Give them back a local channel number. */\r
4842     struct ssh_channel *c;\r
4843     int remoteid = ssh_pkt_getuint32(pktin);\r
4845     /* Refuse if agent forwarding is disabled. */\r
4846     if (!ssh->agentfwd_enabled) {\r
4847         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4848                     PKT_INT, remoteid, PKT_END);\r
4849     } else {\r
4850         c = snew(struct ssh_channel);\r
4851         c->ssh = ssh;\r
4852         c->remoteid = remoteid;\r
4853         c->halfopen = FALSE;\r
4854         c->localid = alloc_channel_id(ssh);\r
4855         c->closes = 0;\r
4856         c->pending_eof = FALSE;\r
4857         c->throttling_conn = 0;\r
4858         c->type = CHAN_AGENT;   /* identify channel type */\r
4859         c->u.a.lensofar = 0;\r
4860         c->u.a.message = NULL;\r
4861         c->u.a.outstanding_requests = 0;\r
4862         add234(ssh->channels, c);\r
4863         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4864                     PKT_INT, c->remoteid, PKT_INT, c->localid,\r
4865                     PKT_END);\r
4866     }\r
4869 static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)\r
4871     /* Remote side is trying to open a channel to talk to a\r
4872      * forwarded port. Give them back a local channel number. */\r
4873     struct ssh_rportfwd pf, *pfp;\r
4874     int remoteid;\r
4875     int hostsize, port;\r
4876     char *host;\r
4877     const char *e;\r
4879     remoteid = ssh_pkt_getuint32(pktin);\r
4880     ssh_pkt_getstring(pktin, &host, &hostsize);\r
4881     port = ssh_pkt_getuint32(pktin);\r
4883     if (hostsize >= lenof(pf.dhost))\r
4884         hostsize = lenof(pf.dhost)-1;\r
4885     memcpy(pf.dhost, host, hostsize);\r
4886     pf.dhost[hostsize] = '\0';\r
4887     pf.dport = port;\r
4888     pfp = find234(ssh->rportfwds, &pf, NULL);\r
4890     if (pfp == NULL) {\r
4891         logeventf(ssh, "Rejected remote port open request for %s:%d",\r
4892                   pf.dhost, port);\r
4893         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4894                     PKT_INT, remoteid, PKT_END);\r
4895     } else {\r
4896         struct ssh_channel *c = snew(struct ssh_channel);\r
4897         c->ssh = ssh;\r
4899         logeventf(ssh, "Received remote port open request for %s:%d",\r
4900                   pf.dhost, port);\r
4901         e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,\r
4902                            c, ssh->conf, pfp->pfrec->addressfamily);\r
4903         if (e != NULL) {\r
4904             logeventf(ssh, "Port open failed: %s", e);\r
4905             sfree(c);\r
4906             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4907                         PKT_INT, remoteid, PKT_END);\r
4908         } else {\r
4909             c->remoteid = remoteid;\r
4910             c->halfopen = FALSE;\r
4911             c->localid = alloc_channel_id(ssh);\r
4912             c->closes = 0;\r
4913             c->pending_eof = FALSE;\r
4914             c->throttling_conn = 0;\r
4915             c->type = CHAN_SOCKDATA;    /* identify channel type */\r
4916             add234(ssh->channels, c);\r
4917             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4918                         PKT_INT, c->remoteid, PKT_INT,\r
4919                         c->localid, PKT_END);\r
4920             logevent("Forwarded port opened successfully");\r
4921         }\r
4922     }\r
4925 static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
4927     unsigned int remoteid = ssh_pkt_getuint32(pktin);\r
4928     unsigned int localid = ssh_pkt_getuint32(pktin);\r
4929     struct ssh_channel *c;\r
4931     c = find234(ssh->channels, &remoteid, ssh_channelfind);\r
4932     if (c && c->type == CHAN_SOCKDATA_DORMANT) {\r
4933         c->remoteid = localid;\r
4934         c->halfopen = FALSE;\r
4935         c->type = CHAN_SOCKDATA;\r
4936         c->throttling_conn = 0;\r
4937         pfd_confirm(c->u.pfd.s);\r
4938     }\r
4940     if (c && c->pending_eof) {\r
4941         /*\r
4942          * We have a pending close on this channel,\r
4943          * which we decided on before the server acked\r
4944          * the channel open. So now we know the\r
4945          * remoteid, we can close it again.\r
4946          */\r
4947         ssh_channel_try_eof(c);\r
4948     }\r
4951 static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
4953     unsigned int remoteid = ssh_pkt_getuint32(pktin);\r
4954     struct ssh_channel *c;\r
4956     c = find234(ssh->channels, &remoteid, ssh_channelfind);\r
4957     if (c && c->type == CHAN_SOCKDATA_DORMANT) {\r
4958         logevent("Forwarded connection refused by server");\r
4959         pfd_close(c->u.pfd.s);\r
4960         del234(ssh->channels, c);\r
4961         sfree(c);\r
4962     }\r
4965 static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
4967     /* Remote side closes a channel. */\r
4968     unsigned i = ssh_pkt_getuint32(pktin);\r
4969     struct ssh_channel *c;\r
4970     c = find234(ssh->channels, &i, ssh_channelfind);\r
4971     if (c && !c->halfopen) {\r
4973         if (pktin->type == SSH1_MSG_CHANNEL_CLOSE &&\r
4974             !(c->closes & CLOSES_RCVD_EOF)) {\r
4975             /*\r
4976              * Received CHANNEL_CLOSE, which we translate into\r
4977              * outgoing EOF.\r
4978              */\r
4979             int send_close = FALSE;\r
4981             c->closes |= CLOSES_RCVD_EOF;\r
4983             switch (c->type) {\r
4984               case CHAN_X11:\r
4985                 if (c->u.x11.s)\r
4986                     x11_send_eof(c->u.x11.s);\r
4987                 else\r
4988                     send_close = TRUE;\r
4989                 break;\r
4990               case CHAN_SOCKDATA:\r
4991                 if (c->u.pfd.s)\r
4992                     pfd_send_eof(c->u.pfd.s);\r
4993                 else\r
4994                     send_close = TRUE;\r
4995                 break;\r
4996               case CHAN_AGENT:\r
4997                 send_close = TRUE;\r
4998                 break;\r
4999             }\r
5001             if (send_close && !(c->closes & CLOSES_SENT_EOF)) {\r
5002                 send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,\r
5003                             PKT_END);\r
5004                 c->closes |= CLOSES_SENT_EOF;\r
5005             }\r
5006         }\r
5008         if (pktin->type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION &&\r
5009             !(c->closes & CLOSES_RCVD_CLOSE)) {\r
5011             if (!(c->closes & CLOSES_SENT_EOF)) {\r
5012                 bombout(("Received CHANNEL_CLOSE_CONFIRMATION for channel %d"\r
5013                          " for which we never sent CHANNEL_CLOSE\n", i));\r
5014             }\r
5016             c->closes |= CLOSES_RCVD_CLOSE;\r
5017         }\r
5019         if (!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) &&\r
5020             !(c->closes & CLOSES_SENT_CLOSE)) {\r
5021             send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION,\r
5022                         PKT_INT, c->remoteid, PKT_END);\r
5023             c->closes |= CLOSES_SENT_CLOSE;\r
5024         }\r
5026         if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes))\r
5027             ssh_channel_destroy(c);\r
5028     } else {\r
5029         bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",\r
5030                  pktin->type == SSH1_MSG_CHANNEL_CLOSE ? "" :\r
5031                  "_CONFIRMATION", c ? "half-open" : "nonexistent",\r
5032                  i));\r
5033     }\r
5036 static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
5038     /* Data sent down one of our channels. */\r
5039     int i = ssh_pkt_getuint32(pktin);\r
5040     char *p;\r
5041     int len;\r
5042     struct ssh_channel *c;\r
5044     ssh_pkt_getstring(pktin, &p, &len);\r
5046     c = find234(ssh->channels, &i, ssh_channelfind);\r
5047     if (c) {\r
5048         int bufsize = 0;\r
5049         switch (c->type) {\r
5050           case CHAN_X11:\r
5051             bufsize = x11_send(c->u.x11.s, p, len);\r
5052             break;\r
5053           case CHAN_SOCKDATA:\r
5054             bufsize = pfd_send(c->u.pfd.s, p, len);\r
5055             break;\r
5056           case CHAN_AGENT:\r
5057             /* Data for an agent message. Buffer it. */\r
5058             while (len > 0) {\r
5059                 if (c->u.a.lensofar < 4) {\r
5060                     unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len);\r
5061                     memcpy(c->u.a.msglen + c->u.a.lensofar, p,\r
5062                            l);\r
5063                     p += l;\r
5064                     len -= l;\r
5065                     c->u.a.lensofar += l;\r
5066                 }\r
5067                 if (c->u.a.lensofar == 4) {\r
5068                     c->u.a.totallen =\r
5069                         4 + GET_32BIT(c->u.a.msglen);\r
5070                     c->u.a.message = snewn(c->u.a.totallen,\r
5071                                            unsigned char);\r
5072                     memcpy(c->u.a.message, c->u.a.msglen, 4);\r
5073                 }\r
5074                 if (c->u.a.lensofar >= 4 && len > 0) {\r
5075                     unsigned int l =\r
5076                         min(c->u.a.totallen - c->u.a.lensofar,\r
5077                             (unsigned)len);\r
5078                     memcpy(c->u.a.message + c->u.a.lensofar, p,\r
5079                            l);\r
5080                     p += l;\r
5081                     len -= l;\r
5082                     c->u.a.lensofar += l;\r
5083                 }\r
5084                 if (c->u.a.lensofar == c->u.a.totallen) {\r
5085                     void *reply;\r
5086                     int replylen;\r
5087                     c->u.a.outstanding_requests++;\r
5088                     if (agent_query(c->u.a.message,\r
5089                                     c->u.a.totallen,\r
5090                                     &reply, &replylen,\r
5091                                     ssh_agentf_callback, c))\r
5092                         ssh_agentf_callback(c, reply, replylen);\r
5093                     sfree(c->u.a.message);\r
5094                     c->u.a.lensofar = 0;\r
5095                 }\r
5096             }\r
5097             bufsize = 0;   /* agent channels never back up */\r
5098             break;\r
5099         }\r
5100         if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {\r
5101             c->throttling_conn = 1;\r
5102             ssh_throttle_conn(ssh, +1);\r
5103         }\r
5104     }\r
5107 static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin)\r
5109     ssh->exitcode = ssh_pkt_getuint32(pktin);\r
5110     logeventf(ssh, "Server sent command exit status %d", ssh->exitcode);\r
5111     send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);\r
5112     /*\r
5113      * In case `helpful' firewalls or proxies tack\r
5114      * extra human-readable text on the end of the\r
5115      * session which we might mistake for another\r
5116      * encrypted packet, we close the session once\r
5117      * we've sent EXIT_CONFIRMATION.\r
5118      */\r
5119     ssh_disconnect(ssh, NULL, NULL, 0, TRUE);\r
5122 /* Helper function to deal with sending tty modes for REQUEST_PTY */\r
5123 static void ssh1_send_ttymode(void *data, char *mode, char *val)\r
5125     struct Packet *pktout = (struct Packet *)data;\r
5126     int i = 0;\r
5127     unsigned int arg = 0;\r
5128     while (strcmp(mode, ssh_ttymodes[i].mode) != 0) i++;\r
5129     if (i == lenof(ssh_ttymodes)) return;\r
5130     switch (ssh_ttymodes[i].type) {\r
5131       case TTY_OP_CHAR:\r
5132         arg = ssh_tty_parse_specchar(val);\r
5133         break;\r
5134       case TTY_OP_BOOL:\r
5135         arg = ssh_tty_parse_boolean(val);\r
5136         break;\r
5137     }\r
5138     ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode);\r
5139     ssh2_pkt_addbyte(pktout, arg);\r
5143 static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen,\r
5144                                struct Packet *pktin)\r
5146     crBegin(ssh->do_ssh1_connection_crstate);\r
5148     ssh->packet_dispatch[SSH1_SMSG_STDOUT_DATA] = \r
5149         ssh->packet_dispatch[SSH1_SMSG_STDERR_DATA] =\r
5150         ssh1_smsg_stdout_stderr_data;\r
5152     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
5153         ssh1_msg_channel_open_confirmation;\r
5154     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_FAILURE] =\r
5155         ssh1_msg_channel_open_failure;\r
5156     ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE] =\r
5157         ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION] =\r
5158         ssh1_msg_channel_close;\r
5159     ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data;\r
5160     ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status;\r
5162     if (conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) {\r
5163         logevent("Requesting agent forwarding");\r
5164         send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);\r
5165         do {\r
5166             crReturnV;\r
5167         } while (!pktin);\r
5168         if (pktin->type != SSH1_SMSG_SUCCESS\r
5169             && pktin->type != SSH1_SMSG_FAILURE) {\r
5170             bombout(("Protocol confusion"));\r
5171             crStopV;\r
5172         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5173             logevent("Agent forwarding refused");\r
5174         } else {\r
5175             logevent("Agent forwarding enabled");\r
5176             ssh->agentfwd_enabled = TRUE;\r
5177             ssh->packet_dispatch[SSH1_SMSG_AGENT_OPEN] = ssh1_smsg_agent_open;\r
5178         }\r
5179     }\r
5181     if (conf_get_int(ssh->conf, CONF_x11_forward) &&\r
5182         (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),\r
5183                                           conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) {\r
5184         logevent("Requesting X11 forwarding");\r
5185         /*\r
5186          * Note that while we blank the X authentication data here, we don't\r
5187          * take any special action to blank the start of an X11 channel,\r
5188          * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection\r
5189          * without having session blanking enabled is likely to leak your\r
5190          * cookie into the log.\r
5191          */\r
5192         if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {\r
5193             send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5194                         PKT_STR, ssh->x11disp->remoteauthprotoname,\r
5195                         PKTT_PASSWORD,\r
5196                         PKT_STR, ssh->x11disp->remoteauthdatastring,\r
5197                         PKTT_OTHER,\r
5198                         PKT_INT, ssh->x11disp->screennum,\r
5199                         PKT_END);\r
5200         } else {\r
5201             send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5202                         PKT_STR, ssh->x11disp->remoteauthprotoname,\r
5203                         PKTT_PASSWORD,\r
5204                         PKT_STR, ssh->x11disp->remoteauthdatastring,\r
5205                         PKTT_OTHER,\r
5206                         PKT_END);\r
5207         }\r
5208         do {\r
5209             crReturnV;\r
5210         } while (!pktin);\r
5211         if (pktin->type != SSH1_SMSG_SUCCESS\r
5212             && pktin->type != SSH1_SMSG_FAILURE) {\r
5213             bombout(("Protocol confusion"));\r
5214             crStopV;\r
5215         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5216             logevent("X11 forwarding refused");\r
5217         } else {\r
5218             logevent("X11 forwarding enabled");\r
5219             ssh->X11_fwd_enabled = TRUE;\r
5220             ssh->packet_dispatch[SSH1_SMSG_X11_OPEN] = ssh1_smsg_x11_open;\r
5221         }\r
5222     }\r
5224     ssh_setup_portfwd(ssh, ssh->conf);\r
5225     ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open;\r
5227     if (!conf_get_int(ssh->conf, CONF_nopty)) {\r
5228         struct Packet *pkt;\r
5229         /* Unpick the terminal-speed string. */\r
5230         /* XXX perhaps we should allow no speeds to be sent. */\r
5231         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
5232         sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
5233         /* Send the pty request. */\r
5234         pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY);\r
5235         ssh_pkt_addstring(pkt, conf_get_str(ssh->conf, CONF_termtype));\r
5236         ssh_pkt_adduint32(pkt, ssh->term_height);\r
5237         ssh_pkt_adduint32(pkt, ssh->term_width);\r
5238         ssh_pkt_adduint32(pkt, 0); /* width in pixels */\r
5239         ssh_pkt_adduint32(pkt, 0); /* height in pixels */\r
5240         parse_ttymodes(ssh, ssh1_send_ttymode, (void *)pkt);\r
5241         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_ISPEED);\r
5242         ssh_pkt_adduint32(pkt, ssh->ispeed);\r
5243         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_OSPEED);\r
5244         ssh_pkt_adduint32(pkt, ssh->ospeed);\r
5245         ssh_pkt_addbyte(pkt, SSH_TTY_OP_END);\r
5246         s_wrpkt(ssh, pkt);\r
5247         ssh->state = SSH_STATE_INTERMED;\r
5248         do {\r
5249             crReturnV;\r
5250         } while (!pktin);\r
5251         if (pktin->type != SSH1_SMSG_SUCCESS\r
5252             && pktin->type != SSH1_SMSG_FAILURE) {\r
5253             bombout(("Protocol confusion"));\r
5254             crStopV;\r
5255         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5256             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
5257             ssh->editing = ssh->echoing = 1;\r
5258         } else {\r
5259             logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
5260                       ssh->ospeed, ssh->ispeed);\r
5261             ssh->got_pty = TRUE;\r
5262         }\r
5263     } else {\r
5264         ssh->editing = ssh->echoing = 1;\r
5265     }\r
5267     if (conf_get_int(ssh->conf, CONF_compression)) {\r
5268         send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);\r
5269         do {\r
5270             crReturnV;\r
5271         } while (!pktin);\r
5272         if (pktin->type != SSH1_SMSG_SUCCESS\r
5273             && pktin->type != SSH1_SMSG_FAILURE) {\r
5274             bombout(("Protocol confusion"));\r
5275             crStopV;\r
5276         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5277             c_write_str(ssh, "Server refused to compress\r\n");\r
5278         }\r
5279         logevent("Started compression");\r
5280         ssh->v1_compressing = TRUE;\r
5281         ssh->cs_comp_ctx = zlib_compress_init();\r
5282         logevent("Initialised zlib (RFC1950) compression");\r
5283         ssh->sc_comp_ctx = zlib_decompress_init();\r
5284         logevent("Initialised zlib (RFC1950) decompression");\r
5285     }\r
5287     /*\r
5288      * Start the shell or command.\r
5289      * \r
5290      * Special case: if the first-choice command is an SSH-2\r
5291      * subsystem (hence not usable here) and the second choice\r
5292      * exists, we fall straight back to that.\r
5293      */\r
5294     {\r
5295         char *cmd = conf_get_str(ssh->conf, CONF_remote_cmd);\r
5296         \r
5297         if (conf_get_int(ssh->conf, CONF_ssh_subsys) &&\r
5298             conf_get_str(ssh->conf, CONF_remote_cmd2)) {\r
5299             cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);\r
5300             ssh->fallback_cmd = TRUE;\r
5301         }\r
5302         if (*cmd)\r
5303             send_packet(ssh, SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);\r
5304         else\r
5305             send_packet(ssh, SSH1_CMSG_EXEC_SHELL, PKT_END);\r
5306         logevent("Started session");\r
5307     }\r
5309     ssh->state = SSH_STATE_SESSION;\r
5310     if (ssh->size_needed)\r
5311         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
5312     if (ssh->eof_needed)\r
5313         ssh_special(ssh, TS_EOF);\r
5315     if (ssh->ldisc)\r
5316         ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */\r
5317     ssh->send_ok = 1;\r
5318     ssh->channels = newtree234(ssh_channelcmp);\r
5319     while (1) {\r
5321         /*\r
5322          * By this point, most incoming packets are already being\r
5323          * handled by the dispatch table, and we need only pay\r
5324          * attention to the unusual ones.\r
5325          */\r
5327         crReturnV;\r
5328         if (pktin) {\r
5329             if (pktin->type == SSH1_SMSG_SUCCESS) {\r
5330                 /* may be from EXEC_SHELL on some servers */\r
5331             } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5332                 /* may be from EXEC_SHELL on some servers\r
5333                  * if no pty is available or in other odd cases. Ignore */\r
5334             } else {\r
5335                 bombout(("Strange packet received: type %d", pktin->type));\r
5336                 crStopV;\r
5337             }\r
5338         } else {\r
5339             while (inlen > 0) {\r
5340                 int len = min(inlen, 512);\r
5341                 send_packet(ssh, SSH1_CMSG_STDIN_DATA,\r
5342                             PKT_INT, len,  PKTT_DATA, PKT_DATA, in, len,\r
5343                             PKTT_OTHER, PKT_END);\r
5344                 in += len;\r
5345                 inlen -= len;\r
5346             }\r
5347         }\r
5348     }\r
5350     crFinishV;\r
5353 /*\r
5354  * Handle the top-level SSH-2 protocol.\r
5355  */\r
5356 static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin)\r
5358     char *msg;\r
5359     int msglen;\r
5361     ssh_pkt_getstring(pktin, &msg, &msglen);\r
5362     logeventf(ssh, "Remote debug message: %.*s", msglen, msg);\r
5365 static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
5367     /* log reason code in disconnect message */\r
5368     char *msg;\r
5369     int msglen;\r
5371     ssh_pkt_getstring(pktin, &msg, &msglen);\r
5372     bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));\r
5375 static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)\r
5377     /* Do nothing, because we're ignoring it! Duhh. */\r
5380 static void ssh1_protocol_setup(Ssh ssh)\r
5382     int i;\r
5384     /*\r
5385      * Most messages are handled by the coroutines.\r
5386      */\r
5387     for (i = 0; i < 256; i++)\r
5388         ssh->packet_dispatch[i] = NULL;\r
5390     /*\r
5391      * These special message types we install handlers for.\r
5392      */\r
5393     ssh->packet_dispatch[SSH1_MSG_DISCONNECT] = ssh1_msg_disconnect;\r
5394     ssh->packet_dispatch[SSH1_MSG_IGNORE] = ssh_msg_ignore;\r
5395     ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug;\r
5398 static void ssh1_protocol(Ssh ssh, void *vin, int inlen,\r
5399                           struct Packet *pktin)\r
5401     unsigned char *in=(unsigned char*)vin;\r
5402     if (ssh->state == SSH_STATE_CLOSED)\r
5403         return;\r
5405     if (pktin && ssh->packet_dispatch[pktin->type]) {\r
5406         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
5407         return;\r
5408     }\r
5410     if (!ssh->protocol_initial_phase_done) {\r
5411         if (do_ssh1_login(ssh, in, inlen, pktin))\r
5412             ssh->protocol_initial_phase_done = TRUE;\r
5413         else\r
5414             return;\r
5415     }\r
5417     do_ssh1_connection(ssh, in, inlen, pktin);\r
5420 /*\r
5421  * Utility routine for decoding comma-separated strings in KEXINIT.\r
5422  */\r
5423 static int in_commasep_string(char *needle, char *haystack, int haylen)\r
5425     int needlen;\r
5426     if (!needle || !haystack)          /* protect against null pointers */\r
5427         return 0;\r
5428     needlen = strlen(needle);\r
5429     while (1) {\r
5430         /*\r
5431          * Is it at the start of the string?\r
5432          */\r
5433         if (haylen >= needlen &&       /* haystack is long enough */\r
5434             !memcmp(needle, haystack, needlen) &&       /* initial match */\r
5435             (haylen == needlen || haystack[needlen] == ',')\r
5436             /* either , or EOS follows */\r
5437             )\r
5438             return 1;\r
5439         /*\r
5440          * If not, search for the next comma and resume after that.\r
5441          * If no comma found, terminate.\r
5442          */\r
5443         while (haylen > 0 && *haystack != ',')\r
5444             haylen--, haystack++;\r
5445         if (haylen == 0)\r
5446             return 0;\r
5447         haylen--, haystack++;          /* skip over comma itself */\r
5448     }\r
5451 /*\r
5452  * Similar routine for checking whether we have the first string in a list.\r
5453  */\r
5454 static int first_in_commasep_string(char *needle, char *haystack, int haylen)\r
5456     int needlen;\r
5457     if (!needle || !haystack)          /* protect against null pointers */\r
5458         return 0;\r
5459     needlen = strlen(needle);\r
5460     /*\r
5461      * Is it at the start of the string?\r
5462      */\r
5463     if (haylen >= needlen &&       /* haystack is long enough */\r
5464         !memcmp(needle, haystack, needlen) &&   /* initial match */\r
5465         (haylen == needlen || haystack[needlen] == ',')\r
5466         /* either , or EOS follows */\r
5467         )\r
5468         return 1;\r
5469     return 0;\r
5473 /*\r
5474  * SSH-2 key creation method.\r
5475  * (Currently assumes 2 lots of any hash are sufficient to generate\r
5476  * keys/IVs for any cipher/MAC. SSH2_MKKEY_ITERS documents this assumption.)\r
5477  */\r
5478 #define SSH2_MKKEY_ITERS (2)\r
5479 static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr,\r
5480                        unsigned char *keyspace)\r
5482     const struct ssh_hash *h = ssh->kex->hash;\r
5483     void *s;\r
5484     /* First hlen bytes. */\r
5485     s = h->init();\r
5486     if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
5487         hash_mpint(h, s, K);\r
5488     h->bytes(s, H, h->hlen);\r
5489     h->bytes(s, &chr, 1);\r
5490     h->bytes(s, ssh->v2_session_id, ssh->v2_session_id_len);\r
5491     h->final(s, keyspace);\r
5492     /* Next hlen bytes. */\r
5493     s = h->init();\r
5494     if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
5495         hash_mpint(h, s, K);\r
5496     h->bytes(s, H, h->hlen);\r
5497     h->bytes(s, keyspace, h->hlen);\r
5498     h->final(s, keyspace + h->hlen);\r
5501 /*\r
5502  * Handle the SSH-2 transport layer.\r
5503  */\r
5504 static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,\r
5505                              struct Packet *pktin)\r
5507     unsigned char *in = (unsigned char *)vin;\r
5508     struct do_ssh2_transport_state {\r
5509         int crLine;\r
5510         int nbits, pbits, warn_kex, warn_cscipher, warn_sccipher;\r
5511         Bignum p, g, e, f, K;\r
5512         void *our_kexinit;\r
5513         int our_kexinitlen;\r
5514         int kex_init_value, kex_reply_value;\r
5515         const struct ssh_mac **maclist;\r
5516         int nmacs;\r
5517         const struct ssh2_cipher *cscipher_tobe;\r
5518         const struct ssh2_cipher *sccipher_tobe;\r
5519         const struct ssh_mac *csmac_tobe;\r
5520         const struct ssh_mac *scmac_tobe;\r
5521         const struct ssh_compress *cscomp_tobe;\r
5522         const struct ssh_compress *sccomp_tobe;\r
5523         char *hostkeydata, *sigdata, *rsakeydata, *keystr, *fingerprint;\r
5524         int hostkeylen, siglen, rsakeylen;\r
5525         void *hkey;                    /* actual host key */\r
5526         void *rsakey;                  /* for RSA kex */\r
5527         unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN];\r
5528         int n_preferred_kex;\r
5529         const struct ssh_kexes *preferred_kex[KEX_MAX];\r
5530         int n_preferred_ciphers;\r
5531         const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];\r
5532         const struct ssh_compress *preferred_comp;\r
5533         int userauth_succeeded;     /* for delayed compression */\r
5534         int pending_compression;\r
5535         int got_session_id, activated_authconn;\r
5536         struct Packet *pktout;\r
5537         int dlgret;\r
5538         int guessok;\r
5539         int ignorepkt;\r
5540     };\r
5541     crState(do_ssh2_transport_state);\r
5543     crBeginState;\r
5545     s->cscipher_tobe = s->sccipher_tobe = NULL;\r
5546     s->csmac_tobe = s->scmac_tobe = NULL;\r
5547     s->cscomp_tobe = s->sccomp_tobe = NULL;\r
5549     s->got_session_id = s->activated_authconn = FALSE;\r
5550     s->userauth_succeeded = FALSE;\r
5551     s->pending_compression = FALSE;\r
5553     /*\r
5554      * Be prepared to work around the buggy MAC problem.\r
5555      */\r
5556     if (ssh->remote_bugs & BUG_SSH2_HMAC)\r
5557         s->maclist = buggymacs, s->nmacs = lenof(buggymacs);\r
5558     else\r
5559         s->maclist = macs, s->nmacs = lenof(macs);\r
5561   begin_key_exchange:\r
5562     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
5563     {\r
5564         int i, j, k, commalist_started;\r
5566         /*\r
5567          * Set up the preferred key exchange. (NULL => warn below here)\r
5568          */\r
5569         s->n_preferred_kex = 0;\r
5570         for (i = 0; i < KEX_MAX; i++) {\r
5571             switch (conf_get_int_int(ssh->conf, CONF_ssh_kexlist, i)) {\r
5572               case KEX_DHGEX:\r
5573                 s->preferred_kex[s->n_preferred_kex++] =\r
5574                     &ssh_diffiehellman_gex;\r
5575                 break;\r
5576               case KEX_DHGROUP14:\r
5577                 s->preferred_kex[s->n_preferred_kex++] =\r
5578                     &ssh_diffiehellman_group14;\r
5579                 break;\r
5580               case KEX_DHGROUP1:\r
5581                 s->preferred_kex[s->n_preferred_kex++] =\r
5582                     &ssh_diffiehellman_group1;\r
5583                 break;\r
5584               case KEX_RSA:\r
5585                 s->preferred_kex[s->n_preferred_kex++] =\r
5586                     &ssh_rsa_kex;\r
5587                 break;\r
5588               case KEX_WARN:\r
5589                 /* Flag for later. Don't bother if it's the last in\r
5590                  * the list. */\r
5591                 if (i < KEX_MAX - 1) {\r
5592                     s->preferred_kex[s->n_preferred_kex++] = NULL;\r
5593                 }\r
5594                 break;\r
5595             }\r
5596         }\r
5598         /*\r
5599          * Set up the preferred ciphers. (NULL => warn below here)\r
5600          */\r
5601         s->n_preferred_ciphers = 0;\r
5602         for (i = 0; i < CIPHER_MAX; i++) {\r
5603             switch (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i)) {\r
5604               case CIPHER_BLOWFISH:\r
5605                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish;\r
5606                 break;\r
5607               case CIPHER_DES:\r
5608                 if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc)) {\r
5609                     s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des;\r
5610                 }\r
5611                 break;\r
5612               case CIPHER_3DES:\r
5613                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des;\r
5614                 break;\r
5615               case CIPHER_AES:\r
5616                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes;\r
5617                 break;\r
5618               case CIPHER_ARCFOUR:\r
5619                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour;\r
5620                 break;\r
5621               case CIPHER_WARN:\r
5622                 /* Flag for later. Don't bother if it's the last in\r
5623                  * the list. */\r
5624                 if (i < CIPHER_MAX - 1) {\r
5625                     s->preferred_ciphers[s->n_preferred_ciphers++] = NULL;\r
5626                 }\r
5627                 break;\r
5628             }\r
5629         }\r
5631         /*\r
5632          * Set up preferred compression.\r
5633          */\r
5634         if (conf_get_int(ssh->conf, CONF_compression))\r
5635             s->preferred_comp = &ssh_zlib;\r
5636         else\r
5637             s->preferred_comp = &ssh_comp_none;\r
5639         /*\r
5640          * Enable queueing of outgoing auth- or connection-layer\r
5641          * packets while we are in the middle of a key exchange.\r
5642          */\r
5643         ssh->queueing = TRUE;\r
5645         /*\r
5646          * Flag that KEX is in progress.\r
5647          */\r
5648         ssh->kex_in_progress = TRUE;\r
5650         /*\r
5651          * Construct and send our key exchange packet.\r
5652          */\r
5653         s->pktout = ssh2_pkt_init(SSH2_MSG_KEXINIT);\r
5654         for (i = 0; i < 16; i++)\r
5655             ssh2_pkt_addbyte(s->pktout, (unsigned char) random_byte());\r
5656         /* List key exchange algorithms. */\r
5657         ssh2_pkt_addstring_start(s->pktout);\r
5658         commalist_started = 0;\r
5659         for (i = 0; i < s->n_preferred_kex; i++) {\r
5660             const struct ssh_kexes *k = s->preferred_kex[i];\r
5661             if (!k) continue;          /* warning flag */\r
5662             for (j = 0; j < k->nkexes; j++) {\r
5663                 if (commalist_started)\r
5664                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5665                 ssh2_pkt_addstring_str(s->pktout, k->list[j]->name);\r
5666                 commalist_started = 1;\r
5667             }\r
5668         }\r
5669         /* List server host key algorithms. */\r
5670         ssh2_pkt_addstring_start(s->pktout);\r
5671         for (i = 0; i < lenof(hostkey_algs); i++) {\r
5672             ssh2_pkt_addstring_str(s->pktout, hostkey_algs[i]->name);\r
5673             if (i < lenof(hostkey_algs) - 1)\r
5674                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5675         }\r
5676         /* List encryption algorithms (client->server then server->client). */\r
5677         for (k = 0; k < 2; k++) {\r
5678             ssh2_pkt_addstring_start(s->pktout);\r
5679             commalist_started = 0;\r
5680             for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5681                 const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5682                 if (!c) continue;              /* warning flag */\r
5683                 for (j = 0; j < c->nciphers; j++) {\r
5684                     if (commalist_started)\r
5685                         ssh2_pkt_addstring_str(s->pktout, ",");\r
5686                     ssh2_pkt_addstring_str(s->pktout, c->list[j]->name);\r
5687                     commalist_started = 1;\r
5688                 }\r
5689             }\r
5690         }\r
5691         /* List MAC algorithms (client->server then server->client). */\r
5692         for (j = 0; j < 2; j++) {\r
5693             ssh2_pkt_addstring_start(s->pktout);\r
5694             for (i = 0; i < s->nmacs; i++) {\r
5695                 ssh2_pkt_addstring_str(s->pktout, s->maclist[i]->name);\r
5696                 if (i < s->nmacs - 1)\r
5697                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5698             }\r
5699         }\r
5700         /* List client->server compression algorithms,\r
5701          * then server->client compression algorithms. (We use the\r
5702          * same set twice.) */\r
5703         for (j = 0; j < 2; j++) {\r
5704             ssh2_pkt_addstring_start(s->pktout);\r
5705             assert(lenof(compressions) > 1);\r
5706             /* Prefer non-delayed versions */\r
5707             ssh2_pkt_addstring_str(s->pktout, s->preferred_comp->name);\r
5708             /* We don't even list delayed versions of algorithms until\r
5709              * they're allowed to be used, to avoid a race. See the end of\r
5710              * this function. */\r
5711             if (s->userauth_succeeded && s->preferred_comp->delayed_name) {\r
5712                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5713                 ssh2_pkt_addstring_str(s->pktout,\r
5714                                        s->preferred_comp->delayed_name);\r
5715             }\r
5716             for (i = 0; i < lenof(compressions); i++) {\r
5717                 const struct ssh_compress *c = compressions[i];\r
5718                 if (c != s->preferred_comp) {\r
5719                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5720                     ssh2_pkt_addstring_str(s->pktout, c->name);\r
5721                     if (s->userauth_succeeded && c->delayed_name) {\r
5722                         ssh2_pkt_addstring_str(s->pktout, ",");\r
5723                         ssh2_pkt_addstring_str(s->pktout, c->delayed_name);\r
5724                     }\r
5725                 }\r
5726             }\r
5727         }\r
5728         /* List client->server languages. Empty list. */\r
5729         ssh2_pkt_addstring_start(s->pktout);\r
5730         /* List server->client languages. Empty list. */\r
5731         ssh2_pkt_addstring_start(s->pktout);\r
5732         /* First KEX packet does _not_ follow, because we're not that brave. */\r
5733         ssh2_pkt_addbool(s->pktout, FALSE);\r
5734         /* Reserved. */\r
5735         ssh2_pkt_adduint32(s->pktout, 0);\r
5736     }\r
5738     s->our_kexinitlen = s->pktout->length - 5;\r
5739     s->our_kexinit = snewn(s->our_kexinitlen, unsigned char);\r
5740     memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); \r
5742     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
5744     if (!pktin)\r
5745         crWaitUntilV(pktin);\r
5747     /*\r
5748      * Now examine the other side's KEXINIT to see what we're up\r
5749      * to.\r
5750      */\r
5751     {\r
5752         char *str, *preferred;\r
5753         int i, j, len;\r
5755         if (pktin->type != SSH2_MSG_KEXINIT) {\r
5756             bombout(("expected key exchange packet from server"));\r
5757             crStopV;\r
5758         }\r
5759         ssh->kex = NULL;\r
5760         ssh->hostkey = NULL;\r
5761         s->cscipher_tobe = NULL;\r
5762         s->sccipher_tobe = NULL;\r
5763         s->csmac_tobe = NULL;\r
5764         s->scmac_tobe = NULL;\r
5765         s->cscomp_tobe = NULL;\r
5766         s->sccomp_tobe = NULL;\r
5767         s->warn_kex = s->warn_cscipher = s->warn_sccipher = FALSE;\r
5769         pktin->savedpos += 16;          /* skip garbage cookie */\r
5770         ssh_pkt_getstring(pktin, &str, &len);    /* key exchange algorithms */\r
5772         preferred = NULL;\r
5773         for (i = 0; i < s->n_preferred_kex; i++) {\r
5774             const struct ssh_kexes *k = s->preferred_kex[i];\r
5775             if (!k) {\r
5776                 s->warn_kex = TRUE;\r
5777             } else {\r
5778                 for (j = 0; j < k->nkexes; j++) {\r
5779                     if (!preferred) preferred = k->list[j]->name;\r
5780                     if (in_commasep_string(k->list[j]->name, str, len)) {\r
5781                         ssh->kex = k->list[j];\r
5782                         break;\r
5783                     }\r
5784                 }\r
5785             }\r
5786             if (ssh->kex)\r
5787                 break;\r
5788         }\r
5789         if (!ssh->kex) {\r
5790             bombout(("Couldn't agree a key exchange algorithm (available: %s)",\r
5791                      str ? str : "(null)"));\r
5792             crStopV;\r
5793         }\r
5794         /*\r
5795          * Note that the server's guess is considered wrong if it doesn't match\r
5796          * the first algorithm in our list, even if it's still the algorithm\r
5797          * we end up using.\r
5798          */\r
5799         s->guessok = first_in_commasep_string(preferred, str, len);\r
5800         ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */\r
5801         for (i = 0; i < lenof(hostkey_algs); i++) {\r
5802             if (in_commasep_string(hostkey_algs[i]->name, str, len)) {\r
5803                 ssh->hostkey = hostkey_algs[i];\r
5804                 break;\r
5805             }\r
5806         }\r
5807         if (!ssh->hostkey) {\r
5808             bombout(("Couldn't agree a host key algorithm (available: %s)",\r
5809                      str ? str : "(null)"));\r
5810             crStopV;\r
5811         }\r
5813         s->guessok = s->guessok &&\r
5814             first_in_commasep_string(hostkey_algs[0]->name, str, len);\r
5815         ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */\r
5816         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5817             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5818             if (!c) {\r
5819                 s->warn_cscipher = TRUE;\r
5820             } else {\r
5821                 for (j = 0; j < c->nciphers; j++) {\r
5822                     if (in_commasep_string(c->list[j]->name, str, len)) {\r
5823                         s->cscipher_tobe = c->list[j];\r
5824                         break;\r
5825                     }\r
5826                 }\r
5827             }\r
5828             if (s->cscipher_tobe)\r
5829                 break;\r
5830         }\r
5831         if (!s->cscipher_tobe) {\r
5832             bombout(("Couldn't agree a client-to-server cipher (available: %s)",\r
5833                      str ? str : "(null)"));\r
5834             crStopV;\r
5835         }\r
5837         ssh_pkt_getstring(pktin, &str, &len);    /* server->client cipher */\r
5838         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5839             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5840             if (!c) {\r
5841                 s->warn_sccipher = TRUE;\r
5842             } else {\r
5843                 for (j = 0; j < c->nciphers; j++) {\r
5844                     if (in_commasep_string(c->list[j]->name, str, len)) {\r
5845                         s->sccipher_tobe = c->list[j];\r
5846                         break;\r
5847                     }\r
5848                 }\r
5849             }\r
5850             if (s->sccipher_tobe)\r
5851                 break;\r
5852         }\r
5853         if (!s->sccipher_tobe) {\r
5854             bombout(("Couldn't agree a server-to-client cipher (available: %s)",\r
5855                      str ? str : "(null)"));\r
5856             crStopV;\r
5857         }\r
5859         ssh_pkt_getstring(pktin, &str, &len);    /* client->server mac */\r
5860         for (i = 0; i < s->nmacs; i++) {\r
5861             if (in_commasep_string(s->maclist[i]->name, str, len)) {\r
5862                 s->csmac_tobe = s->maclist[i];\r
5863                 break;\r
5864             }\r
5865         }\r
5866         ssh_pkt_getstring(pktin, &str, &len);    /* server->client mac */\r
5867         for (i = 0; i < s->nmacs; i++) {\r
5868             if (in_commasep_string(s->maclist[i]->name, str, len)) {\r
5869                 s->scmac_tobe = s->maclist[i];\r
5870                 break;\r
5871             }\r
5872         }\r
5873         ssh_pkt_getstring(pktin, &str, &len);  /* client->server compression */\r
5874         for (i = 0; i < lenof(compressions) + 1; i++) {\r
5875             const struct ssh_compress *c =\r
5876                 i == 0 ? s->preferred_comp : compressions[i - 1];\r
5877             if (in_commasep_string(c->name, str, len)) {\r
5878                 s->cscomp_tobe = c;\r
5879                 break;\r
5880             } else if (in_commasep_string(c->delayed_name, str, len)) {\r
5881                 if (s->userauth_succeeded) {\r
5882                     s->cscomp_tobe = c;\r
5883                     break;\r
5884                 } else {\r
5885                     s->pending_compression = TRUE;  /* try this later */\r
5886                 }\r
5887             }\r
5888         }\r
5889         ssh_pkt_getstring(pktin, &str, &len);  /* server->client compression */\r
5890         for (i = 0; i < lenof(compressions) + 1; i++) {\r
5891             const struct ssh_compress *c =\r
5892                 i == 0 ? s->preferred_comp : compressions[i - 1];\r
5893             if (in_commasep_string(c->name, str, len)) {\r
5894                 s->sccomp_tobe = c;\r
5895                 break;\r
5896             } else if (in_commasep_string(c->delayed_name, str, len)) {\r
5897                 if (s->userauth_succeeded) {\r
5898                     s->sccomp_tobe = c;\r
5899                     break;\r
5900                 } else {\r
5901                     s->pending_compression = TRUE;  /* try this later */\r
5902                 }\r
5903             }\r
5904         }\r
5905         if (s->pending_compression) {\r
5906             logevent("Server supports delayed compression; "\r
5907                      "will try this later");\r
5908         }\r
5909         ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */\r
5910         ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */\r
5911         s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok;\r
5913         ssh->exhash = ssh->kex->hash->init();\r
5914         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c));\r
5915         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s));\r
5916         hash_string(ssh->kex->hash, ssh->exhash,\r
5917             s->our_kexinit, s->our_kexinitlen);\r
5918         sfree(s->our_kexinit);\r
5919         if (pktin->length > 5)\r
5920             hash_string(ssh->kex->hash, ssh->exhash,\r
5921                 pktin->data + 5, pktin->length - 5);\r
5923         if (s->warn_kex) {\r
5924             ssh_set_frozen(ssh, 1);\r
5925             s->dlgret = askalg(ssh->frontend, "key-exchange algorithm",\r
5926                                ssh->kex->name,\r
5927                                ssh_dialog_callback, ssh);\r
5928             if (s->dlgret < 0) {\r
5929                 do {\r
5930                     crReturnV;\r
5931                     if (pktin) {\r
5932                         bombout(("Unexpected data from server while"\r
5933                                  " waiting for user response"));\r
5934                         crStopV;\r
5935                     }\r
5936                 } while (pktin || inlen > 0);\r
5937                 s->dlgret = ssh->user_response;\r
5938             }\r
5939             ssh_set_frozen(ssh, 0);\r
5940             if (s->dlgret == 0) {\r
5941                 ssh_disconnect(ssh, "User aborted at kex warning", NULL,\r
5942                                0, TRUE);\r
5943                 crStopV;\r
5944             }\r
5945         }\r
5947         if (s->warn_cscipher) {\r
5948             ssh_set_frozen(ssh, 1);\r
5949             s->dlgret = askalg(ssh->frontend,\r
5950                                "client-to-server cipher",\r
5951                                s->cscipher_tobe->name,\r
5952                                ssh_dialog_callback, ssh);\r
5953             if (s->dlgret < 0) {\r
5954                 do {\r
5955                     crReturnV;\r
5956                     if (pktin) {\r
5957                         bombout(("Unexpected data from server while"\r
5958                                  " waiting for user response"));\r
5959                         crStopV;\r
5960                     }\r
5961                 } while (pktin || inlen > 0);\r
5962                 s->dlgret = ssh->user_response;\r
5963             }\r
5964             ssh_set_frozen(ssh, 0);\r
5965             if (s->dlgret == 0) {\r
5966                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
5967                                0, TRUE);\r
5968                 crStopV;\r
5969             }\r
5970         }\r
5972         if (s->warn_sccipher) {\r
5973             ssh_set_frozen(ssh, 1);\r
5974             s->dlgret = askalg(ssh->frontend,\r
5975                                "server-to-client cipher",\r
5976                                s->sccipher_tobe->name,\r
5977                                ssh_dialog_callback, ssh);\r
5978             if (s->dlgret < 0) {\r
5979                 do {\r
5980                     crReturnV;\r
5981                     if (pktin) {\r
5982                         bombout(("Unexpected data from server while"\r
5983                                  " waiting for user response"));\r
5984                         crStopV;\r
5985                     }\r
5986                 } while (pktin || inlen > 0);\r
5987                 s->dlgret = ssh->user_response;\r
5988             }\r
5989             ssh_set_frozen(ssh, 0);\r
5990             if (s->dlgret == 0) {\r
5991                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
5992                                0, TRUE);\r
5993                 crStopV;\r
5994             }\r
5995         }\r
5997         if (s->ignorepkt) /* first_kex_packet_follows */\r
5998             crWaitUntilV(pktin);                /* Ignore packet */\r
5999     }\r
6001     if (ssh->kex->main_type == KEXTYPE_DH) {\r
6002         /*\r
6003          * Work out the number of bits of key we will need from the\r
6004          * key exchange. We start with the maximum key length of\r
6005          * either cipher...\r
6006          */\r
6007         {\r
6008             int csbits, scbits;\r
6010             csbits = s->cscipher_tobe->keylen;\r
6011             scbits = s->sccipher_tobe->keylen;\r
6012             s->nbits = (csbits > scbits ? csbits : scbits);\r
6013         }\r
6014         /* The keys only have hlen-bit entropy, since they're based on\r
6015          * a hash. So cap the key size at hlen bits. */\r
6016         if (s->nbits > ssh->kex->hash->hlen * 8)\r
6017             s->nbits = ssh->kex->hash->hlen * 8;\r
6019         /*\r
6020          * If we're doing Diffie-Hellman group exchange, start by\r
6021          * requesting a group.\r
6022          */\r
6023         if (!ssh->kex->pdata) {\r
6024             logevent("Doing Diffie-Hellman group exchange");\r
6025             ssh->pkt_kctx = SSH2_PKTCTX_DHGEX;\r
6026             /*\r
6027              * Work out how big a DH group we will need to allow that\r
6028              * much data.\r
6029              */\r
6030             s->pbits = 512 << ((s->nbits - 1) / 64);\r
6031             s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);\r
6032             ssh2_pkt_adduint32(s->pktout, s->pbits);\r
6033             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6035             crWaitUntilV(pktin);\r
6036             if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) {\r
6037                 bombout(("expected key exchange group packet from server"));\r
6038                 crStopV;\r
6039             }\r
6040             s->p = ssh2_pkt_getmp(pktin);\r
6041             s->g = ssh2_pkt_getmp(pktin);\r
6042             if (!s->p || !s->g) {\r
6043                 bombout(("unable to read mp-ints from incoming group packet"));\r
6044                 crStopV;\r
6045             }\r
6046             ssh->kex_ctx = dh_setup_gex(s->p, s->g);\r
6047             s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;\r
6048             s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;\r
6049         } else {\r
6050             ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP;\r
6051             ssh->kex_ctx = dh_setup_group(ssh->kex);\r
6052             s->kex_init_value = SSH2_MSG_KEXDH_INIT;\r
6053             s->kex_reply_value = SSH2_MSG_KEXDH_REPLY;\r
6054             logeventf(ssh, "Using Diffie-Hellman with standard group \"%s\"",\r
6055                       ssh->kex->groupname);\r
6056         }\r
6058         logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s",\r
6059                   ssh->kex->hash->text_name);\r
6060         /*\r
6061          * Now generate and send e for Diffie-Hellman.\r
6062          */\r
6063         set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */\r
6064         s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2);\r
6065         s->pktout = ssh2_pkt_init(s->kex_init_value);\r
6066         ssh2_pkt_addmp(s->pktout, s->e);\r
6067         ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6069         set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */\r
6070         crWaitUntilV(pktin);\r
6071         if (pktin->type != s->kex_reply_value) {\r
6072             bombout(("expected key exchange reply packet from server"));\r
6073             crStopV;\r
6074         }\r
6075         set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */\r
6076         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
6077         s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen);\r
6078         s->f = ssh2_pkt_getmp(pktin);\r
6079         if (!s->f) {\r
6080             bombout(("unable to parse key exchange reply packet"));\r
6081             crStopV;\r
6082         }\r
6083         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
6085         s->K = dh_find_K(ssh->kex_ctx, s->f);\r
6087         /* We assume everything from now on will be quick, and it might\r
6088          * involve user interaction. */\r
6089         set_busy_status(ssh->frontend, BUSY_NOT);\r
6091         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);\r
6092         if (!ssh->kex->pdata) {\r
6093             hash_uint32(ssh->kex->hash, ssh->exhash, s->pbits);\r
6094             hash_mpint(ssh->kex->hash, ssh->exhash, s->p);\r
6095             hash_mpint(ssh->kex->hash, ssh->exhash, s->g);\r
6096         }\r
6097         hash_mpint(ssh->kex->hash, ssh->exhash, s->e);\r
6098         hash_mpint(ssh->kex->hash, ssh->exhash, s->f);\r
6100         dh_cleanup(ssh->kex_ctx);\r
6101         freebn(s->f);\r
6102         if (!ssh->kex->pdata) {\r
6103             freebn(s->g);\r
6104             freebn(s->p);\r
6105         }\r
6106     } else {\r
6107         logeventf(ssh, "Doing RSA key exchange with hash %s",\r
6108                   ssh->kex->hash->text_name);\r
6109         ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX;\r
6110         /*\r
6111          * RSA key exchange. First expect a KEXRSA_PUBKEY packet\r
6112          * from the server.\r
6113          */\r
6114         crWaitUntilV(pktin);\r
6115         if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) {\r
6116             bombout(("expected RSA public key packet from server"));\r
6117             crStopV;\r
6118         }\r
6120         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
6121         hash_string(ssh->kex->hash, ssh->exhash,\r
6122                     s->hostkeydata, s->hostkeylen);\r
6123         s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen);\r
6125         {\r
6126             char *keydata;\r
6127             ssh_pkt_getstring(pktin, &keydata, &s->rsakeylen);\r
6128             s->rsakeydata = snewn(s->rsakeylen, char);\r
6129             memcpy(s->rsakeydata, keydata, s->rsakeylen);\r
6130         }\r
6132         s->rsakey = ssh_rsakex_newkey(s->rsakeydata, s->rsakeylen);\r
6133         if (!s->rsakey) {\r
6134             sfree(s->rsakeydata);\r
6135             bombout(("unable to parse RSA public key from server"));\r
6136             crStopV;\r
6137         }\r
6139         hash_string(ssh->kex->hash, ssh->exhash, s->rsakeydata, s->rsakeylen);\r
6141         /*\r
6142          * Next, set up a shared secret K, of precisely KLEN -\r
6143          * 2*HLEN - 49 bits, where KLEN is the bit length of the\r
6144          * RSA key modulus and HLEN is the bit length of the hash\r
6145          * we're using.\r
6146          */\r
6147         {\r
6148             int klen = ssh_rsakex_klen(s->rsakey);\r
6149             int nbits = klen - (2*ssh->kex->hash->hlen*8 + 49);\r
6150             int i, byte = 0;\r
6151             unsigned char *kstr1, *kstr2, *outstr;\r
6152             int kstr1len, kstr2len, outstrlen;\r
6154             s->K = bn_power_2(nbits - 1);\r
6156             for (i = 0; i < nbits; i++) {\r
6157                 if ((i & 7) == 0) {\r
6158                     byte = random_byte();\r
6159                 }\r
6160                 bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1);\r
6161             }\r
6163             /*\r
6164              * Encode this as an mpint.\r
6165              */\r
6166             kstr1 = ssh2_mpint_fmt(s->K, &kstr1len);\r
6167             kstr2 = snewn(kstr2len = 4 + kstr1len, unsigned char);\r
6168             PUT_32BIT(kstr2, kstr1len);\r
6169             memcpy(kstr2 + 4, kstr1, kstr1len);\r
6171             /*\r
6172              * Encrypt it with the given RSA key.\r
6173              */\r
6174             outstrlen = (klen + 7) / 8;\r
6175             outstr = snewn(outstrlen, unsigned char);\r
6176             ssh_rsakex_encrypt(ssh->kex->hash, kstr2, kstr2len,\r
6177                                outstr, outstrlen, s->rsakey);\r
6179             /*\r
6180              * And send it off in a return packet.\r
6181              */\r
6182             s->pktout = ssh2_pkt_init(SSH2_MSG_KEXRSA_SECRET);\r
6183             ssh2_pkt_addstring_start(s->pktout);\r
6184             ssh2_pkt_addstring_data(s->pktout, (char *)outstr, outstrlen);\r
6185             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6187             hash_string(ssh->kex->hash, ssh->exhash, outstr, outstrlen);\r
6189             sfree(kstr2);\r
6190             sfree(kstr1);\r
6191             sfree(outstr);\r
6192         }\r
6194         ssh_rsakex_freekey(s->rsakey);\r
6196         crWaitUntilV(pktin);\r
6197         if (pktin->type != SSH2_MSG_KEXRSA_DONE) {\r
6198             sfree(s->rsakeydata);\r
6199             bombout(("expected signature packet from server"));\r
6200             crStopV;\r
6201         }\r
6203         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
6205         sfree(s->rsakeydata);\r
6206     }\r
6208     hash_mpint(ssh->kex->hash, ssh->exhash, s->K);\r
6209     assert(ssh->kex->hash->hlen <= sizeof(s->exchange_hash));\r
6210     ssh->kex->hash->final(ssh->exhash, s->exchange_hash);\r
6212     ssh->kex_ctx = NULL;\r
6214 #if 0\r
6215     debug(("Exchange hash is:\n"));\r
6216     dmemdump(s->exchange_hash, ssh->kex->hash->hlen);\r
6217 #endif\r
6219     if (!s->hkey ||\r
6220         !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,\r
6221                                  (char *)s->exchange_hash,\r
6222                                  ssh->kex->hash->hlen)) {\r
6223         bombout(("Server's host key did not match the signature supplied"));\r
6224         crStopV;\r
6225     }\r
6227     /*\r
6228      * Authenticate remote host: verify host key. (We've already\r
6229      * checked the signature of the exchange hash.)\r
6230      */\r
6231     s->keystr = ssh->hostkey->fmtkey(s->hkey);\r
6232     s->fingerprint = ssh->hostkey->fingerprint(s->hkey);\r
6233     ssh_set_frozen(ssh, 1);\r
6234     s->dlgret = verify_ssh_host_key(ssh->frontend,\r
6235                                     ssh->savedhost, ssh->savedport,\r
6236                                     ssh->hostkey->keytype, s->keystr,\r
6237                                     s->fingerprint,\r
6238                                     ssh_dialog_callback, ssh);\r
6239     if (s->dlgret < 0) {\r
6240         do {\r
6241             crReturnV;\r
6242             if (pktin) {\r
6243                 bombout(("Unexpected data from server while waiting"\r
6244                          " for user host key response"));\r
6245                     crStopV;\r
6246             }\r
6247         } while (pktin || inlen > 0);\r
6248         s->dlgret = ssh->user_response;\r
6249     }\r
6250     ssh_set_frozen(ssh, 0);\r
6251     if (s->dlgret == 0) {\r
6252         ssh_disconnect(ssh, "User aborted at host key verification", NULL,\r
6253                        0, TRUE);\r
6254         crStopV;\r
6255     }\r
6256     if (!s->got_session_id) {     /* don't bother logging this in rekeys */\r
6257         logevent("Host key fingerprint is:");\r
6258         logevent(s->fingerprint);\r
6259     }\r
6260     sfree(s->fingerprint);\r
6261     sfree(s->keystr);\r
6262     ssh->hostkey->freekey(s->hkey);\r
6264     /*\r
6265      * The exchange hash from the very first key exchange is also\r
6266      * the session id, used in session key construction and\r
6267      * authentication.\r
6268      */\r
6269     if (!s->got_session_id) {\r
6270         assert(sizeof(s->exchange_hash) <= sizeof(ssh->v2_session_id));\r
6271         memcpy(ssh->v2_session_id, s->exchange_hash,\r
6272                sizeof(s->exchange_hash));\r
6273         ssh->v2_session_id_len = ssh->kex->hash->hlen;\r
6274         assert(ssh->v2_session_id_len <= sizeof(ssh->v2_session_id));\r
6275         s->got_session_id = TRUE;\r
6276     }\r
6278     /*\r
6279      * Send SSH2_MSG_NEWKEYS.\r
6280      */\r
6281     s->pktout = ssh2_pkt_init(SSH2_MSG_NEWKEYS);\r
6282     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6283     ssh->outgoing_data_size = 0;       /* start counting from here */\r
6285     /*\r
6286      * We've sent client NEWKEYS, so create and initialise\r
6287      * client-to-server session keys.\r
6288      */\r
6289     if (ssh->cs_cipher_ctx)\r
6290         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
6291     ssh->cscipher = s->cscipher_tobe;\r
6292     ssh->cs_cipher_ctx = ssh->cscipher->make_context();\r
6294     if (ssh->cs_mac_ctx)\r
6295         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
6296     ssh->csmac = s->csmac_tobe;\r
6297     ssh->cs_mac_ctx = ssh->csmac->make_context();\r
6299     if (ssh->cs_comp_ctx)\r
6300         ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
6301     ssh->cscomp = s->cscomp_tobe;\r
6302     ssh->cs_comp_ctx = ssh->cscomp->compress_init();\r
6304     /*\r
6305      * Set IVs on client-to-server keys. Here we use the exchange\r
6306      * hash from the _first_ key exchange.\r
6307      */\r
6308     {\r
6309         unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];\r
6310         assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6311         ssh2_mkkey(ssh,s->K,s->exchange_hash,'C',keyspace);\r
6312         assert((ssh->cscipher->keylen+7) / 8 <=\r
6313                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6314         ssh->cscipher->setkey(ssh->cs_cipher_ctx, keyspace);\r
6315         ssh2_mkkey(ssh,s->K,s->exchange_hash,'A',keyspace);\r
6316         assert(ssh->cscipher->blksize <=\r
6317                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6318         ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace);\r
6319         ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace);\r
6320         assert(ssh->csmac->len <=\r
6321                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6322         ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace);\r
6323         smemclr(keyspace, sizeof(keyspace));\r
6324     }\r
6326     logeventf(ssh, "Initialised %.200s client->server encryption",\r
6327               ssh->cscipher->text_name);\r
6328     logeventf(ssh, "Initialised %.200s client->server MAC algorithm",\r
6329               ssh->csmac->text_name);\r
6330     if (ssh->cscomp->text_name)\r
6331         logeventf(ssh, "Initialised %s compression",\r
6332                   ssh->cscomp->text_name);\r
6334     /*\r
6335      * Now our end of the key exchange is complete, we can send all\r
6336      * our queued higher-layer packets.\r
6337      */\r
6338     ssh->queueing = FALSE;\r
6339     ssh2_pkt_queuesend(ssh);\r
6341     /*\r
6342      * Expect SSH2_MSG_NEWKEYS from server.\r
6343      */\r
6344     crWaitUntilV(pktin);\r
6345     if (pktin->type != SSH2_MSG_NEWKEYS) {\r
6346         bombout(("expected new-keys packet from server"));\r
6347         crStopV;\r
6348     }\r
6349     ssh->incoming_data_size = 0;       /* start counting from here */\r
6351     /*\r
6352      * We've seen server NEWKEYS, so create and initialise\r
6353      * server-to-client session keys.\r
6354      */\r
6355     if (ssh->sc_cipher_ctx)\r
6356         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
6357     ssh->sccipher = s->sccipher_tobe;\r
6358     ssh->sc_cipher_ctx = ssh->sccipher->make_context();\r
6360     if (ssh->sc_mac_ctx)\r
6361         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
6362     ssh->scmac = s->scmac_tobe;\r
6363     ssh->sc_mac_ctx = ssh->scmac->make_context();\r
6365     if (ssh->sc_comp_ctx)\r
6366         ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
6367     ssh->sccomp = s->sccomp_tobe;\r
6368     ssh->sc_comp_ctx = ssh->sccomp->decompress_init();\r
6370     /*\r
6371      * Set IVs on server-to-client keys. Here we use the exchange\r
6372      * hash from the _first_ key exchange.\r
6373      */\r
6374     {\r
6375         unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];\r
6376         assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6377         ssh2_mkkey(ssh,s->K,s->exchange_hash,'D',keyspace);\r
6378         assert((ssh->sccipher->keylen+7) / 8 <=\r
6379                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6380         ssh->sccipher->setkey(ssh->sc_cipher_ctx, keyspace);\r
6381         ssh2_mkkey(ssh,s->K,s->exchange_hash,'B',keyspace);\r
6382         assert(ssh->sccipher->blksize <=\r
6383                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6384         ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace);\r
6385         ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace);\r
6386         assert(ssh->scmac->len <=\r
6387                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6388         ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace);\r
6389         smemclr(keyspace, sizeof(keyspace));\r
6390     }\r
6391     logeventf(ssh, "Initialised %.200s server->client encryption",\r
6392               ssh->sccipher->text_name);\r
6393     logeventf(ssh, "Initialised %.200s server->client MAC algorithm",\r
6394               ssh->scmac->text_name);\r
6395     if (ssh->sccomp->text_name)\r
6396         logeventf(ssh, "Initialised %s decompression",\r
6397                   ssh->sccomp->text_name);\r
6399     /*\r
6400      * Free shared secret.\r
6401      */\r
6402     freebn(s->K);\r
6404     /*\r
6405      * Key exchange is over. Loop straight back round if we have a\r
6406      * deferred rekey reason.\r
6407      */\r
6408     if (ssh->deferred_rekey_reason) {\r
6409         logevent(ssh->deferred_rekey_reason);\r
6410         pktin = NULL;\r
6411         ssh->deferred_rekey_reason = NULL;\r
6412         goto begin_key_exchange;\r
6413     }\r
6415     /*\r
6416      * Otherwise, schedule a timer for our next rekey.\r
6417      */\r
6418     ssh->kex_in_progress = FALSE;\r
6419     ssh->last_rekey = GETTICKCOUNT();\r
6420     if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0)\r
6421         ssh->next_rekey = schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC,\r
6422                                          ssh2_timer, ssh);\r
6424     /*\r
6425      * Now we're encrypting. Begin returning 1 to the protocol main\r
6426      * function so that other things can run on top of the\r
6427      * transport. If we ever see a KEXINIT, we must go back to the\r
6428      * start.\r
6429      * \r
6430      * We _also_ go back to the start if we see pktin==NULL and\r
6431      * inlen negative, because this is a special signal meaning\r
6432      * `initiate client-driven rekey', and `in' contains a message\r
6433      * giving the reason for the rekey.\r
6434      *\r
6435      * inlen==-1 means always initiate a rekey;\r
6436      * inlen==-2 means that userauth has completed successfully and\r
6437      *   we should consider rekeying (for delayed compression).\r
6438      */\r
6439     while (!((pktin && pktin->type == SSH2_MSG_KEXINIT) ||\r
6440              (!pktin && inlen < 0))) {\r
6441         wait_for_rekey:\r
6442         if (!ssh->protocol_initial_phase_done) {\r
6443             ssh->protocol_initial_phase_done = TRUE;\r
6444             /*\r
6445              * Allow authconn to initialise itself.\r
6446              */\r
6447             do_ssh2_authconn(ssh, NULL, 0, NULL);\r
6448         }\r
6449         crReturnV;\r
6450     }\r
6451     if (pktin) {\r
6452         logevent("Server initiated key re-exchange");\r
6453     } else {\r
6454         if (inlen == -2) {\r
6455             /* \r
6456              * authconn has seen a USERAUTH_SUCCEEDED. Time to enable\r
6457              * delayed compression, if it's available.\r
6458              *\r
6459              * draft-miller-secsh-compression-delayed-00 says that you\r
6460              * negotiate delayed compression in the first key exchange, and\r
6461              * both sides start compressing when the server has sent\r
6462              * USERAUTH_SUCCESS. This has a race condition -- the server\r
6463              * can't know when the client has seen it, and thus which incoming\r
6464              * packets it should treat as compressed.\r
6465              *\r
6466              * Instead, we do the initial key exchange without offering the\r
6467              * delayed methods, but note if the server offers them; when we\r
6468              * get here, if a delayed method was available that was higher\r
6469              * on our list than what we got, we initiate a rekey in which we\r
6470              * _do_ list the delayed methods (and hopefully get it as a\r
6471              * result). Subsequent rekeys will do the same.\r
6472              */\r
6473             assert(!s->userauth_succeeded); /* should only happen once */\r
6474             s->userauth_succeeded = TRUE;\r
6475             if (!s->pending_compression)\r
6476                 /* Can't see any point rekeying. */\r
6477                 goto wait_for_rekey;       /* this is utterly horrid */\r
6478             /* else fall through to rekey... */\r
6479             s->pending_compression = FALSE;\r
6480         }\r
6481         /*\r
6482          * Now we've decided to rekey.\r
6483          *\r
6484          * Special case: if the server bug is set that doesn't\r
6485          * allow rekeying, we give a different log message and\r
6486          * continue waiting. (If such a server _initiates_ a rekey,\r
6487          * we process it anyway!)\r
6488          */\r
6489         if ((ssh->remote_bugs & BUG_SSH2_REKEY)) {\r
6490             logeventf(ssh, "Server bug prevents key re-exchange (%s)",\r
6491                       (char *)in);\r
6492             /* Reset the counters, so that at least this message doesn't\r
6493              * hit the event log _too_ often. */\r
6494             ssh->outgoing_data_size = 0;\r
6495             ssh->incoming_data_size = 0;\r
6496             if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0) {\r
6497                 ssh->next_rekey =\r
6498                     schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC,\r
6499                                    ssh2_timer, ssh);\r
6500             }\r
6501             goto wait_for_rekey;       /* this is still utterly horrid */\r
6502         } else {\r
6503             logeventf(ssh, "Initiating key re-exchange (%s)", (char *)in);\r
6504         }\r
6505     }\r
6506     goto begin_key_exchange;\r
6508     crFinishV;\r
6511 /*\r
6512  * Add data to an SSH-2 channel output buffer.\r
6513  */\r
6514 static void ssh2_add_channel_data(struct ssh_channel *c, char *buf,\r
6515                                   int len)\r
6517     bufchain_add(&c->v.v2.outbuffer, buf, len);\r
6520 /*\r
6521  * Attempt to send data on an SSH-2 channel.\r
6522  */\r
6523 static int ssh2_try_send(struct ssh_channel *c)\r
6525     Ssh ssh = c->ssh;\r
6526     struct Packet *pktout;\r
6527     int ret;\r
6529     while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) {\r
6530         int len;\r
6531         void *data;\r
6532         bufchain_prefix(&c->v.v2.outbuffer, &data, &len);\r
6533         if ((unsigned)len > c->v.v2.remwindow)\r
6534             len = c->v.v2.remwindow;\r
6535         if ((unsigned)len > c->v.v2.remmaxpkt)\r
6536             len = c->v.v2.remmaxpkt;\r
6537         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);\r
6538         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6539         ssh2_pkt_addstring_start(pktout);\r
6540         dont_log_data(ssh, pktout, PKTLOG_OMIT);\r
6541         ssh2_pkt_addstring_data(pktout, data, len);\r
6542         end_log_omission(ssh, pktout);\r
6543         ssh2_pkt_send(ssh, pktout);\r
6544         bufchain_consume(&c->v.v2.outbuffer, len);\r
6545         c->v.v2.remwindow -= len;\r
6546     }\r
6548     /*\r
6549      * After having sent as much data as we can, return the amount\r
6550      * still buffered.\r
6551      */\r
6552     ret = bufchain_size(&c->v.v2.outbuffer);\r
6554     /*\r
6555      * And if there's no data pending but we need to send an EOF, send\r
6556      * it.\r
6557      */\r
6558     if (!ret && c->pending_eof)\r
6559         ssh_channel_try_eof(c);\r
6561     return ret;\r
6564 static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c)\r
6566     int bufsize;\r
6567     if (c->closes & CLOSES_SENT_EOF)\r
6568         return;                   /* don't send on channels we've EOFed */\r
6569     bufsize = ssh2_try_send(c);\r
6570     if (bufsize == 0) {\r
6571         switch (c->type) {\r
6572           case CHAN_MAINSESSION:\r
6573             /* stdin need not receive an unthrottle\r
6574              * notification since it will be polled */\r
6575             break;\r
6576           case CHAN_X11:\r
6577             x11_unthrottle(c->u.x11.s);\r
6578             break;\r
6579           case CHAN_AGENT:\r
6580             /* agent sockets are request/response and need no\r
6581              * buffer management */\r
6582             break;\r
6583           case CHAN_SOCKDATA:\r
6584             pfd_unthrottle(c->u.pfd.s);\r
6585             break;\r
6586         }\r
6587     }\r
6590 /*\r
6591  * Set up most of a new ssh_channel for SSH-2.\r
6592  */\r
6593 static void ssh2_channel_init(struct ssh_channel *c)\r
6595     Ssh ssh = c->ssh;\r
6596     c->localid = alloc_channel_id(ssh);\r
6597     c->closes = 0;\r
6598     c->pending_eof = FALSE;\r
6599     c->throttling_conn = FALSE;\r
6600     c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =\r
6601         conf_get_int(ssh->conf, CONF_ssh_simple) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;\r
6602     c->v.v2.chanreq_head = NULL;\r
6603     c->v.v2.throttle_state = UNTHROTTLED;\r
6604     bufchain_init(&c->v.v2.outbuffer);\r
6607 /*\r
6608  * Construct the common parts of a CHANNEL_OPEN.\r
6609  */\r
6610 static struct Packet *ssh2_chanopen_init(struct ssh_channel *c, char *type)\r
6612     struct Packet *pktout;\r
6614     pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);\r
6615     ssh2_pkt_addstring(pktout, type);\r
6616     ssh2_pkt_adduint32(pktout, c->localid);\r
6617     ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */\r
6618     ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
6619     return pktout;\r
6622 /*\r
6623  * CHANNEL_FAILURE doesn't come with any indication of what message\r
6624  * caused it, so we have to keep track of the outstanding\r
6625  * CHANNEL_REQUESTs ourselves.\r
6626  */\r
6627 static void ssh2_queue_chanreq_handler(struct ssh_channel *c,\r
6628                                        cchandler_fn_t handler, void *ctx)\r
6630     struct outstanding_channel_request *ocr =\r
6631         snew(struct outstanding_channel_request);\r
6633     assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));\r
6634     ocr->handler = handler;\r
6635     ocr->ctx = ctx;\r
6636     ocr->next = NULL;\r
6637     if (!c->v.v2.chanreq_head)\r
6638         c->v.v2.chanreq_head = ocr;\r
6639     else\r
6640         c->v.v2.chanreq_tail->next = ocr;\r
6641     c->v.v2.chanreq_tail = ocr;\r
6644 /*\r
6645  * Construct the common parts of a CHANNEL_REQUEST.  If handler is not\r
6646  * NULL then a reply will be requested and the handler will be called\r
6647  * when it arrives.  The returned packet is ready to have any\r
6648  * request-specific data added and be sent.  Note that if a handler is\r
6649  * provided, it's essential that the request actually be sent.\r
6650  *\r
6651  * The handler will usually be passed the response packet in pktin.\r
6652  * If pktin is NULL, this means that no reply will ever be forthcoming\r
6653  * (e.g. because the entire connection is being destroyed) and the\r
6654  * handler should free any storage it's holding.\r
6655  */\r
6656 static struct Packet *ssh2_chanreq_init(struct ssh_channel *c, char *type,\r
6657                                         cchandler_fn_t handler, void *ctx)\r
6659     struct Packet *pktout;\r
6661     assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));\r
6662     pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
6663     ssh2_pkt_adduint32(pktout, c->remoteid);\r
6664     ssh2_pkt_addstring(pktout, type);\r
6665     ssh2_pkt_addbool(pktout, handler != NULL);\r
6666     if (handler != NULL)\r
6667         ssh2_queue_chanreq_handler(c, handler, ctx);\r
6668     return pktout;\r
6671 /*\r
6672  * Potentially enlarge the window on an SSH-2 channel.\r
6673  */\r
6674 static void ssh2_handle_winadj_response(struct ssh_channel *, struct Packet *,\r
6675                                         void *);\r
6676 static void ssh2_set_window(struct ssh_channel *c, int newwin)\r
6678     Ssh ssh = c->ssh;\r
6680     /*\r
6681      * Never send WINDOW_ADJUST for a channel that the remote side has\r
6682      * already sent EOF on; there's no point, since it won't be\r
6683      * sending any more data anyway. Ditto if _we've_ already sent\r
6684      * CLOSE.\r
6685      */\r
6686     if (c->closes & (CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))\r
6687         return;\r
6689     /*\r
6690      * If the remote end has a habit of ignoring maxpkt, limit the\r
6691      * window so that it has no choice (assuming it doesn't ignore the\r
6692      * window as well).\r
6693      */\r
6694     if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT)\r
6695         newwin = OUR_V2_MAXPKT;\r
6697     /*\r
6698      * Only send a WINDOW_ADJUST if there's significantly more window\r
6699      * available than the other end thinks there is.  This saves us\r
6700      * sending a WINDOW_ADJUST for every character in a shell session.\r
6701      *\r
6702      * "Significant" is arbitrarily defined as half the window size.\r
6703      */\r
6704     if (newwin / 2 >= c->v.v2.locwindow) {\r
6705         struct Packet *pktout;\r
6706         unsigned *up;\r
6708         /*\r
6709          * In order to keep track of how much window the client\r
6710          * actually has available, we'd like it to acknowledge each\r
6711          * WINDOW_ADJUST.  We can't do that directly, so we accompany\r
6712          * it with a CHANNEL_REQUEST that has to be acknowledged.\r
6713          *\r
6714          * This is only necessary if we're opening the window wide.\r
6715          * If we're not, then throughput is being constrained by\r
6716          * something other than the maximum window size anyway.\r
6717          */\r
6718         if (newwin == c->v.v2.locmaxwin &&\r
6719             !(ssh->remote_bugs & BUG_CHOKES_ON_WINADJ)) {\r
6720             up = snew(unsigned);\r
6721             *up = newwin - c->v.v2.locwindow;\r
6722             pktout = ssh2_chanreq_init(c, "winadj@putty.projects.tartarus.org",\r
6723                                        ssh2_handle_winadj_response, up);\r
6724             ssh2_pkt_send(ssh, pktout);\r
6726             if (c->v.v2.throttle_state != UNTHROTTLED)\r
6727                 c->v.v2.throttle_state = UNTHROTTLING;\r
6728         } else {\r
6729             /* Pretend the WINDOW_ADJUST was acked immediately. */\r
6730             c->v.v2.remlocwin = newwin;\r
6731             c->v.v2.throttle_state = THROTTLED;\r
6732         }\r
6733         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
6734         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6735         ssh2_pkt_adduint32(pktout, newwin - c->v.v2.locwindow);\r
6736         ssh2_pkt_send(ssh, pktout);\r
6737         c->v.v2.locwindow = newwin;\r
6738     }\r
6741 /*\r
6742  * Find the channel associated with a message.  If there's no channel,\r
6743  * or it's not properly open, make a noise about it and return NULL.\r
6744  */\r
6745 static struct ssh_channel *ssh2_channel_msg(Ssh ssh, struct Packet *pktin)\r
6747     unsigned localid = ssh_pkt_getuint32(pktin);\r
6748     struct ssh_channel *c;\r
6750     c = find234(ssh->channels, &localid, ssh_channelfind);\r
6751     if (!c ||\r
6752         (c->halfopen && pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION &&\r
6753          pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE)) {\r
6754         char *buf = dupprintf("Received %s for %s channel %u",\r
6755                               ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
6756                                             pktin->type),\r
6757                               c ? "half-open" : "nonexistent", localid);\r
6758         ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
6759         sfree(buf);\r
6760         return NULL;\r
6761     }\r
6762     return c;\r
6765 static void ssh2_handle_winadj_response(struct ssh_channel *c,\r
6766                                         struct Packet *pktin, void *ctx)\r
6768     unsigned *sizep = ctx;\r
6770     /*\r
6771      * Winadj responses should always be failures. However, at least\r
6772      * one server ("boks_sshd") is known to return SUCCESS for channel\r
6773      * requests it's never heard of, such as "winadj@putty". Raised\r
6774      * with foxt.com as bug 090916-090424, but for the sake of a quiet\r
6775      * life, we don't worry about what kind of response we got.\r
6776      */\r
6778     c->v.v2.remlocwin += *sizep;\r
6779     sfree(sizep);\r
6780     /*\r
6781      * winadj messages are only sent when the window is fully open, so\r
6782      * if we get an ack of one, we know any pending unthrottle is\r
6783      * complete.\r
6784      */\r
6785     if (c->v.v2.throttle_state == UNTHROTTLING)\r
6786         c->v.v2.throttle_state = UNTHROTTLED;\r
6789 static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin)\r
6791     struct ssh_channel *c = ssh2_channel_msg(ssh, pktin);\r
6792     struct outstanding_channel_request *ocr;\r
6794     if (!c) return;\r
6795     ocr = c->v.v2.chanreq_head;\r
6796     if (!ocr) {\r
6797         ssh2_msg_unexpected(ssh, pktin);\r
6798         return;\r
6799     }\r
6800     ocr->handler(c, pktin, ocr->ctx);\r
6801     c->v.v2.chanreq_head = ocr->next;\r
6802     sfree(ocr);\r
6803     /*\r
6804      * We may now initiate channel-closing procedures, if that\r
6805      * CHANNEL_REQUEST was the last thing outstanding before we send\r
6806      * CHANNEL_CLOSE.\r
6807      */\r
6808     ssh2_channel_check_close(c);\r
6811 static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)\r
6813     struct ssh_channel *c;\r
6814     c = ssh2_channel_msg(ssh, pktin);\r
6815     if (!c)\r
6816         return;\r
6817     if (!(c->closes & CLOSES_SENT_EOF)) {\r
6818         c->v.v2.remwindow += ssh_pkt_getuint32(pktin);\r
6819         ssh2_try_send_and_unthrottle(ssh, c);\r
6820     }\r
6823 static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
6825     char *data;\r
6826     int length;\r
6827     struct ssh_channel *c;\r
6828     c = ssh2_channel_msg(ssh, pktin);\r
6829     if (!c)\r
6830         return;\r
6831     if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&\r
6832         ssh_pkt_getuint32(pktin) != SSH2_EXTENDED_DATA_STDERR)\r
6833         return;                        /* extended but not stderr */\r
6834     ssh_pkt_getstring(pktin, &data, &length);\r
6835     if (data) {\r
6836         int bufsize = 0;\r
6837         c->v.v2.locwindow -= length;\r
6838         c->v.v2.remlocwin -= length;\r
6839         switch (c->type) {\r
6840           case CHAN_MAINSESSION:\r
6841             bufsize =\r
6842                 from_backend(ssh->frontend, pktin->type ==\r
6843                              SSH2_MSG_CHANNEL_EXTENDED_DATA,\r
6844                              data, length);\r
6845             break;\r
6846           case CHAN_X11:\r
6847             bufsize = x11_send(c->u.x11.s, data, length);\r
6848             break;\r
6849           case CHAN_SOCKDATA:\r
6850             bufsize = pfd_send(c->u.pfd.s, data, length);\r
6851             break;\r
6852           case CHAN_AGENT:\r
6853             while (length > 0) {\r
6854                 if (c->u.a.lensofar < 4) {\r
6855                     unsigned int l = min(4 - c->u.a.lensofar,\r
6856                                          (unsigned)length);\r
6857                     memcpy(c->u.a.msglen + c->u.a.lensofar,\r
6858                            data, l);\r
6859                     data += l;\r
6860                     length -= l;\r
6861                     c->u.a.lensofar += l;\r
6862                 }\r
6863                 if (c->u.a.lensofar == 4) {\r
6864                     c->u.a.totallen =\r
6865                         4 + GET_32BIT(c->u.a.msglen);\r
6866                     c->u.a.message = snewn(c->u.a.totallen,\r
6867                                            unsigned char);\r
6868                     memcpy(c->u.a.message, c->u.a.msglen, 4);\r
6869                 }\r
6870                 if (c->u.a.lensofar >= 4 && length > 0) {\r
6871                     unsigned int l =\r
6872                         min(c->u.a.totallen - c->u.a.lensofar,\r
6873                             (unsigned)length);\r
6874                     memcpy(c->u.a.message + c->u.a.lensofar,\r
6875                            data, l);\r
6876                     data += l;\r
6877                     length -= l;\r
6878                     c->u.a.lensofar += l;\r
6879                 }\r
6880                 if (c->u.a.lensofar == c->u.a.totallen) {\r
6881                     void *reply;\r
6882                     int replylen;\r
6883                     c->u.a.outstanding_requests++;\r
6884                     if (agent_query(c->u.a.message,\r
6885                                     c->u.a.totallen,\r
6886                                     &reply, &replylen,\r
6887                                     ssh_agentf_callback, c))\r
6888                         ssh_agentf_callback(c, reply, replylen);\r
6889                     sfree(c->u.a.message);\r
6890                     c->u.a.message = NULL;\r
6891                     c->u.a.lensofar = 0;\r
6892                 }\r
6893             }\r
6894             bufsize = 0;\r
6895             break;\r
6896         }\r
6897         /*\r
6898          * If it looks like the remote end hit the end of its window,\r
6899          * and we didn't want it to do that, think about using a\r
6900          * larger window.\r
6901          */\r
6902         if (c->v.v2.remlocwin <= 0 && c->v.v2.throttle_state == UNTHROTTLED &&\r
6903             c->v.v2.locmaxwin < 0x40000000)\r
6904             c->v.v2.locmaxwin += OUR_V2_WINSIZE;\r
6905         /*\r
6906          * If we are not buffering too much data,\r
6907          * enlarge the window again at the remote side.\r
6908          * If we are buffering too much, we may still\r
6909          * need to adjust the window if the server's\r
6910          * sent excess data.\r
6911          */\r
6912         ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ?\r
6913                         c->v.v2.locmaxwin - bufsize : 0);\r
6914         /*\r
6915          * If we're either buffering way too much data, or if we're\r
6916          * buffering anything at all and we're in "simple" mode,\r
6917          * throttle the whole channel.\r
6918          */\r
6919         if ((bufsize > c->v.v2.locmaxwin ||\r
6920              (conf_get_int(ssh->conf, CONF_ssh_simple) && bufsize > 0)) &&\r
6921             !c->throttling_conn) {\r
6922             c->throttling_conn = 1;\r
6923             ssh_throttle_conn(ssh, +1);\r
6924         }\r
6925     }\r
6928 static void ssh_channel_destroy(struct ssh_channel *c)\r
6930     Ssh ssh = c->ssh;\r
6932     switch (c->type) {\r
6933       case CHAN_MAINSESSION:\r
6934         ssh->mainchan = NULL;\r
6935         update_specials_menu(ssh->frontend);\r
6936         break;\r
6937       case CHAN_X11:\r
6938         if (c->u.x11.s != NULL)\r
6939             x11_close(c->u.x11.s);\r
6940         logevent("Forwarded X11 connection terminated");\r
6941         break;\r
6942       case CHAN_AGENT:\r
6943         sfree(c->u.a.message);\r
6944         break;\r
6945       case CHAN_SOCKDATA:\r
6946         if (c->u.pfd.s != NULL)\r
6947             pfd_close(c->u.pfd.s);\r
6948         logevent("Forwarded port closed");\r
6949         break;\r
6950     }\r
6952     del234(ssh->channels, c);\r
6953     if (ssh->version == 2) {\r
6954         bufchain_clear(&c->v.v2.outbuffer);\r
6955         assert(c->v.v2.chanreq_head == NULL);\r
6956     }\r
6957     sfree(c);\r
6959     /*\r
6960      * See if that was the last channel left open.\r
6961      * (This is only our termination condition if we're\r
6962      * not running in -N mode.)\r
6963      */\r
6964     if (ssh->version == 2 &&\r
6965         !conf_get_int(ssh->conf, CONF_ssh_no_shell) &&\r
6966         count234(ssh->channels) == 0) {\r
6967         /*\r
6968          * We used to send SSH_MSG_DISCONNECT here,\r
6969          * because I'd believed that _every_ conforming\r
6970          * SSH-2 connection had to end with a disconnect\r
6971          * being sent by at least one side; apparently\r
6972          * I was wrong and it's perfectly OK to\r
6973          * unceremoniously slam the connection shut\r
6974          * when you're done, and indeed OpenSSH feels\r
6975          * this is more polite than sending a\r
6976          * DISCONNECT. So now we don't.\r
6977          */\r
6978         ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE);\r
6979     }\r
6982 static void ssh2_channel_check_close(struct ssh_channel *c)\r
6984     Ssh ssh = c->ssh;\r
6985     struct Packet *pktout;\r
6987     if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) ||\r
6988          c->type == CHAN_ZOMBIE) &&\r
6989         !c->v.v2.chanreq_head &&\r
6990         !(c->closes & CLOSES_SENT_CLOSE)) {\r
6991         /*\r
6992          * We have both sent and received EOF (or the channel is a\r
6993          * zombie), and we have no outstanding channel requests, which\r
6994          * means the channel is in final wind-up. But we haven't sent\r
6995          * CLOSE, so let's do so now.\r
6996          */\r
6997         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
6998         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6999         ssh2_pkt_send(ssh, pktout);\r
7000         c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE;\r
7001     }\r
7003     if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) {\r
7004         assert(c->v.v2.chanreq_head == NULL);\r
7005         /*\r
7006          * We have both sent and received CLOSE, which means we're\r
7007          * completely done with the channel.\r
7008          */\r
7009         ssh_channel_destroy(c);\r
7010     }\r
7013 static void ssh2_channel_got_eof(struct ssh_channel *c)\r
7015     if (c->closes & CLOSES_RCVD_EOF)\r
7016         return;                        /* already seen EOF */\r
7017     c->closes |= CLOSES_RCVD_EOF;\r
7019     if (c->type == CHAN_X11) {\r
7020         x11_send_eof(c->u.x11.s);\r
7021     } else if (c->type == CHAN_AGENT) {\r
7022         if (c->u.a.outstanding_requests == 0) {\r
7023             /* Manufacture an outgoing EOF in response to the incoming one. */\r
7024             sshfwd_write_eof(c);\r
7025         }\r
7026     } else if (c->type == CHAN_SOCKDATA) {\r
7027         pfd_send_eof(c->u.pfd.s);\r
7028     } else if (c->type == CHAN_MAINSESSION) {\r
7029         Ssh ssh = c->ssh;\r
7031         if (!ssh->sent_console_eof &&\r
7032             (from_backend_eof(ssh->frontend) || ssh->got_pty)) {\r
7033             /*\r
7034              * Either from_backend_eof told us that the front end\r
7035              * wants us to close the outgoing side of the connection\r
7036              * as soon as we see EOF from the far end, or else we've\r
7037              * unilaterally decided to do that because we've allocated\r
7038              * a remote pty and hence EOF isn't a particularly\r
7039              * meaningful concept.\r
7040              */\r
7041             sshfwd_write_eof(c);\r
7042         }\r
7043         ssh->sent_console_eof = TRUE;\r
7044     }\r
7046     ssh2_channel_check_close(c);\r
7049 static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin)\r
7051     struct ssh_channel *c;\r
7053     c = ssh2_channel_msg(ssh, pktin);\r
7054     if (!c)\r
7055         return;\r
7056     ssh2_channel_got_eof(c);\r
7059 static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
7061     struct ssh_channel *c;\r
7063     c = ssh2_channel_msg(ssh, pktin);\r
7064     if (!c)\r
7065         return;\r
7067     /*\r
7068      * When we receive CLOSE on a channel, we assume it comes with an\r
7069      * implied EOF if we haven't seen EOF yet.\r
7070      */\r
7071     ssh2_channel_got_eof(c);\r
7073     /*\r
7074      * And we also send an outgoing EOF, if we haven't already, on the\r
7075      * assumption that CLOSE is a pretty forceful announcement that\r
7076      * the remote side is doing away with the entire channel. (If it\r
7077      * had wanted to send us EOF and continue receiving data from us,\r
7078      * it would have just sent CHANNEL_EOF.)\r
7079      */\r
7080     if (!(c->closes & CLOSES_SENT_EOF)) {\r
7081         /*\r
7082          * Make sure we don't read any more from whatever our local\r
7083          * data source is for this channel.\r
7084          */\r
7085         switch (c->type) {\r
7086           case CHAN_MAINSESSION:\r
7087             ssh->send_ok = 0;     /* stop trying to read from stdin */\r
7088             break;\r
7089           case CHAN_X11:\r
7090             x11_override_throttle(c->u.x11.s, 1);\r
7091             break;\r
7092           case CHAN_SOCKDATA:\r
7093             pfd_override_throttle(c->u.pfd.s, 1);\r
7094             break;\r
7095         }\r
7097         /*\r
7098          * Abandon any buffered data we still wanted to send to this\r
7099          * channel. Receiving a CHANNEL_CLOSE is an indication that\r
7100          * the server really wants to get on and _destroy_ this\r
7101          * channel, and it isn't going to send us any further\r
7102          * WINDOW_ADJUSTs to permit us to send pending stuff.\r
7103          */\r
7104         bufchain_clear(&c->v.v2.outbuffer);\r
7106         /*\r
7107          * Send outgoing EOF.\r
7108          */\r
7109         sshfwd_write_eof(c);\r
7110     }\r
7112     /*\r
7113      * Now process the actual close.\r
7114      */\r
7115     if (!(c->closes & CLOSES_RCVD_CLOSE)) {\r
7116         c->closes |= CLOSES_RCVD_CLOSE;\r
7117         ssh2_channel_check_close(c);\r
7118     }\r
7121 static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
7123     struct ssh_channel *c;\r
7125     c = ssh2_channel_msg(ssh, pktin);\r
7126     if (!c)\r
7127         return;\r
7128     if (c->type != CHAN_SOCKDATA_DORMANT)\r
7129         return;                        /* dunno why they're confirming this */\r
7130     c->remoteid = ssh_pkt_getuint32(pktin);\r
7131     c->halfopen = FALSE;\r
7132     c->type = CHAN_SOCKDATA;\r
7133     c->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
7134     c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
7135     if (c->u.pfd.s)\r
7136         pfd_confirm(c->u.pfd.s);\r
7137     if (c->pending_eof)\r
7138         ssh_channel_try_eof(c);\r
7141 static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
7143     static const char *const reasons[] = {\r
7144         "<unknown reason code>",\r
7145             "Administratively prohibited",\r
7146             "Connect failed",\r
7147             "Unknown channel type",\r
7148             "Resource shortage",\r
7149     };\r
7150     unsigned reason_code;\r
7151     char *reason_string;\r
7152     int reason_length;\r
7153     struct ssh_channel *c;\r
7154     c = ssh2_channel_msg(ssh, pktin);\r
7155     if (!c)\r
7156         return;\r
7157     if (c->type != CHAN_SOCKDATA_DORMANT)\r
7158         return;                        /* dunno why they're failing this */\r
7160     reason_code = ssh_pkt_getuint32(pktin);\r
7161     if (reason_code >= lenof(reasons))\r
7162         reason_code = 0; /* ensure reasons[reason_code] in range */\r
7163     ssh_pkt_getstring(pktin, &reason_string, &reason_length);\r
7164     logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",\r
7165               reasons[reason_code], reason_length, reason_string);\r
7167     pfd_close(c->u.pfd.s);\r
7169     del234(ssh->channels, c);\r
7170     sfree(c);\r
7173 static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin)\r
7175     char *type;\r
7176     int typelen, want_reply;\r
7177     int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */\r
7178     struct ssh_channel *c;\r
7179     struct Packet *pktout;\r
7181     c = ssh2_channel_msg(ssh, pktin);\r
7182     if (!c)\r
7183         return;\r
7184     ssh_pkt_getstring(pktin, &type, &typelen);\r
7185     want_reply = ssh2_pkt_getbool(pktin);\r
7187     /*\r
7188      * Having got the channel number, we now look at\r
7189      * the request type string to see if it's something\r
7190      * we recognise.\r
7191      */\r
7192     if (c == ssh->mainchan) {\r
7193         /*\r
7194          * We recognise "exit-status" and "exit-signal" on\r
7195          * the primary channel.\r
7196          */\r
7197         if (typelen == 11 &&\r
7198             !memcmp(type, "exit-status", 11)) {\r
7200             ssh->exitcode = ssh_pkt_getuint32(pktin);\r
7201             logeventf(ssh, "Server sent command exit status %d",\r
7202                       ssh->exitcode);\r
7203             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
7205         } else if (typelen == 11 &&\r
7206                    !memcmp(type, "exit-signal", 11)) {\r
7208             int is_plausible = TRUE, is_int = FALSE;\r
7209             char *fmt_sig = "", *fmt_msg = "";\r
7210             char *msg;\r
7211             int msglen = 0, core = FALSE;\r
7212             /* ICK: older versions of OpenSSH (e.g. 3.4p1)\r
7213              * provide an `int' for the signal, despite its\r
7214              * having been a `string' in the drafts of RFC 4254 since at\r
7215              * least 2001. (Fixed in session.c 1.147.) Try to\r
7216              * infer which we can safely parse it as. */\r
7217             {\r
7218                 unsigned char *p = pktin->body +\r
7219                     pktin->savedpos;\r
7220                 long len = pktin->length - pktin->savedpos;\r
7221                 unsigned long num = GET_32BIT(p); /* what is it? */\r
7222                 /* If it's 0, it hardly matters; assume string */\r
7223                 if (num == 0) {\r
7224                     is_int = FALSE;\r
7225                 } else {\r
7226                     int maybe_int = FALSE, maybe_str = FALSE;\r
7227 #define CHECK_HYPOTHESIS(offset, result)                                \\r
7228                     do                                                  \\r
7229                     {                                                   \\r
7230                         int q = toint(offset);                          \\r
7231                         if (q >= 0 && q+4 <= len) {                     \\r
7232                             q = toint(q + 4 + GET_32BIT(p+q));          \\r
7233                             if (q >= 0 && q+4 <= len &&                 \\r
7234                                 ((q = toint(q + 4 + GET_32BIT(p+q))) != 0) && \\r
7235                                 q == len)                               \\r
7236                                 result = TRUE;                          \\r
7237                         }                                               \\r
7238                     } while(0)\r
7239                     CHECK_HYPOTHESIS(4+1, maybe_int);\r
7240                     CHECK_HYPOTHESIS(4+num+1, maybe_str);\r
7241 #undef CHECK_HYPOTHESIS\r
7242                     if (maybe_int && !maybe_str)\r
7243                         is_int = TRUE;\r
7244                     else if (!maybe_int && maybe_str)\r
7245                         is_int = FALSE;\r
7246                     else\r
7247                         /* Crikey. Either or neither. Panic. */\r
7248                         is_plausible = FALSE;\r
7249                 }\r
7250             }\r
7251             ssh->exitcode = 128;       /* means `unknown signal' */\r
7252             if (is_plausible) {\r
7253                 if (is_int) {\r
7254                     /* Old non-standard OpenSSH. */\r
7255                     int signum = ssh_pkt_getuint32(pktin);\r
7256                     fmt_sig = dupprintf(" %d", signum);\r
7257                     ssh->exitcode = 128 + signum;\r
7258                 } else {\r
7259                     /* As per RFC 4254. */\r
7260                     char *sig;\r
7261                     int siglen;\r
7262                     ssh_pkt_getstring(pktin, &sig, &siglen);\r
7263                     /* Signal name isn't supposed to be blank, but\r
7264                      * let's cope gracefully if it is. */\r
7265                     if (siglen) {\r
7266                         fmt_sig = dupprintf(" \"%.*s\"",\r
7267                                             siglen, sig);\r
7268                     }\r
7270                     /*\r
7271                      * Really hideous method of translating the\r
7272                      * signal description back into a locally\r
7273                      * meaningful number.\r
7274                      */\r
7276                     if (0)\r
7277                         ;\r
7278 #define TRANSLATE_SIGNAL(s) \\r
7279     else if (siglen == lenof(#s)-1 && !memcmp(sig, #s, siglen)) \\r
7280         ssh->exitcode = 128 + SIG ## s\r
7281 #ifdef SIGABRT\r
7282                     TRANSLATE_SIGNAL(ABRT);\r
7283 #endif\r
7284 #ifdef SIGALRM\r
7285                     TRANSLATE_SIGNAL(ALRM);\r
7286 #endif\r
7287 #ifdef SIGFPE\r
7288                     TRANSLATE_SIGNAL(FPE);\r
7289 #endif\r
7290 #ifdef SIGHUP\r
7291                     TRANSLATE_SIGNAL(HUP);\r
7292 #endif\r
7293 #ifdef SIGILL\r
7294                     TRANSLATE_SIGNAL(ILL);\r
7295 #endif\r
7296 #ifdef SIGINT\r
7297                     TRANSLATE_SIGNAL(INT);\r
7298 #endif\r
7299 #ifdef SIGKILL\r
7300                     TRANSLATE_SIGNAL(KILL);\r
7301 #endif\r
7302 #ifdef SIGPIPE\r
7303                     TRANSLATE_SIGNAL(PIPE);\r
7304 #endif\r
7305 #ifdef SIGQUIT\r
7306                     TRANSLATE_SIGNAL(QUIT);\r
7307 #endif\r
7308 #ifdef SIGSEGV\r
7309                     TRANSLATE_SIGNAL(SEGV);\r
7310 #endif\r
7311 #ifdef SIGTERM\r
7312                     TRANSLATE_SIGNAL(TERM);\r
7313 #endif\r
7314 #ifdef SIGUSR1\r
7315                     TRANSLATE_SIGNAL(USR1);\r
7316 #endif\r
7317 #ifdef SIGUSR2\r
7318                     TRANSLATE_SIGNAL(USR2);\r
7319 #endif\r
7320 #undef TRANSLATE_SIGNAL\r
7321                     else\r
7322                         ssh->exitcode = 128;\r
7323                 }\r
7324                 core = ssh2_pkt_getbool(pktin);\r
7325                 ssh_pkt_getstring(pktin, &msg, &msglen);\r
7326                 if (msglen) {\r
7327                     fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg);\r
7328                 }\r
7329                 /* ignore lang tag */\r
7330             } /* else don't attempt to parse */\r
7331             logeventf(ssh, "Server exited on signal%s%s%s",\r
7332                       fmt_sig, core ? " (core dumped)" : "",\r
7333                       fmt_msg);\r
7334             if (*fmt_sig) sfree(fmt_sig);\r
7335             if (*fmt_msg) sfree(fmt_msg);\r
7336             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
7338         }\r
7339     } else {\r
7340         /*\r
7341          * This is a channel request we don't know\r
7342          * about, so we now either ignore the request\r
7343          * or respond with CHANNEL_FAILURE, depending\r
7344          * on want_reply.\r
7345          */\r
7346         reply = SSH2_MSG_CHANNEL_FAILURE;\r
7347     }\r
7348     if (want_reply) {\r
7349         pktout = ssh2_pkt_init(reply);\r
7350         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7351         ssh2_pkt_send(ssh, pktout);\r
7352     }\r
7355 static void ssh2_msg_global_request(Ssh ssh, struct Packet *pktin)\r
7357     char *type;\r
7358     int typelen, want_reply;\r
7359     struct Packet *pktout;\r
7361     ssh_pkt_getstring(pktin, &type, &typelen);\r
7362     want_reply = ssh2_pkt_getbool(pktin);\r
7364     /*\r
7365      * We currently don't support any global requests\r
7366      * at all, so we either ignore the request or\r
7367      * respond with REQUEST_FAILURE, depending on\r
7368      * want_reply.\r
7369      */\r
7370     if (want_reply) {\r
7371         pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE);\r
7372         ssh2_pkt_send(ssh, pktout);\r
7373     }\r
7376 static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)\r
7378     char *type;\r
7379     int typelen;\r
7380     char *peeraddr;\r
7381     int peeraddrlen;\r
7382     int peerport;\r
7383     char *error = NULL;\r
7384     struct ssh_channel *c;\r
7385     unsigned remid, winsize, pktsize;\r
7386     struct Packet *pktout;\r
7388     ssh_pkt_getstring(pktin, &type, &typelen);\r
7389     c = snew(struct ssh_channel);\r
7390     c->ssh = ssh;\r
7392     remid = ssh_pkt_getuint32(pktin);\r
7393     winsize = ssh_pkt_getuint32(pktin);\r
7394     pktsize = ssh_pkt_getuint32(pktin);\r
7396     if (typelen == 3 && !memcmp(type, "x11", 3)) {\r
7397         char *addrstr;\r
7398         const char *x11err;\r
7400         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
7401         addrstr = snewn(peeraddrlen+1, char);\r
7402         memcpy(addrstr, peeraddr, peeraddrlen);\r
7403         addrstr[peeraddrlen] = '\0';\r
7404         peerport = ssh_pkt_getuint32(pktin);\r
7406         logeventf(ssh, "Received X11 connect request from %s:%d",\r
7407                   addrstr, peerport);\r
7409         if (!ssh->X11_fwd_enabled)\r
7410             error = "X11 forwarding is not enabled";\r
7411         else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,\r
7412                                     addrstr, peerport, ssh->conf)) != NULL) {\r
7413             logeventf(ssh, "Local X11 connection failed: %s", x11err);\r
7414             error = "Unable to open an X11 connection";\r
7415         } else {\r
7416             logevent("Opening X11 forward connection succeeded");\r
7417             c->type = CHAN_X11;\r
7418         }\r
7420         sfree(addrstr);\r
7421     } else if (typelen == 15 &&\r
7422                !memcmp(type, "forwarded-tcpip", 15)) {\r
7423         struct ssh_rportfwd pf, *realpf;\r
7424         char *dummy;\r
7425         int dummylen;\r
7426         ssh_pkt_getstring(pktin, &dummy, &dummylen);/* skip address */\r
7427         pf.sport = ssh_pkt_getuint32(pktin);\r
7428         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
7429         peerport = ssh_pkt_getuint32(pktin);\r
7430         realpf = find234(ssh->rportfwds, &pf, NULL);\r
7431         logeventf(ssh, "Received remote port %d open request "\r
7432                   "from %s:%d", pf.sport, peeraddr, peerport);\r
7433         if (realpf == NULL) {\r
7434             error = "Remote port is not recognised";\r
7435         } else {\r
7436             const char *e = pfd_newconnect(&c->u.pfd.s,\r
7437                                            realpf->dhost,\r
7438                                            realpf->dport, c,\r
7439                                            ssh->conf,\r
7440                                            realpf->pfrec->addressfamily);\r
7441             logeventf(ssh, "Attempting to forward remote port to "\r
7442                       "%s:%d", realpf->dhost, realpf->dport);\r
7443             if (e != NULL) {\r
7444                 logeventf(ssh, "Port open failed: %s", e);\r
7445                 error = "Port open failed";\r
7446             } else {\r
7447                 logevent("Forwarded port opened successfully");\r
7448                 c->type = CHAN_SOCKDATA;\r
7449             }\r
7450         }\r
7451     } else if (typelen == 22 &&\r
7452                !memcmp(type, "auth-agent@openssh.com", 22)) {\r
7453         if (!ssh->agentfwd_enabled)\r
7454             error = "Agent forwarding is not enabled";\r
7455         else {\r
7456             c->type = CHAN_AGENT;       /* identify channel type */\r
7457             c->u.a.lensofar = 0;\r
7458             c->u.a.outstanding_requests = 0;\r
7459         }\r
7460     } else {\r
7461         error = "Unsupported channel type requested";\r
7462     }\r
7464     c->remoteid = remid;\r
7465     c->halfopen = FALSE;\r
7466     if (error) {\r
7467         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
7468         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7469         ssh2_pkt_adduint32(pktout, SSH2_OPEN_CONNECT_FAILED);\r
7470         ssh2_pkt_addstring(pktout, error);\r
7471         ssh2_pkt_addstring(pktout, "en");       /* language tag */\r
7472         ssh2_pkt_send(ssh, pktout);\r
7473         logeventf(ssh, "Rejected channel open: %s", error);\r
7474         sfree(c);\r
7475     } else {\r
7476         ssh2_channel_init(c);\r
7477         c->v.v2.remwindow = winsize;\r
7478         c->v.v2.remmaxpkt = pktsize;\r
7479         add234(ssh->channels, c);\r
7480         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
7481         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7482         ssh2_pkt_adduint32(pktout, c->localid);\r
7483         ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);\r
7484         ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
7485         ssh2_pkt_send(ssh, pktout);\r
7486     }\r
7489 /*\r
7490  * Buffer banner messages for later display at some convenient point,\r
7491  * if we're going to display them.\r
7492  */\r
7493 static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin)\r
7495     /* Arbitrary limit to prevent unbounded inflation of buffer */\r
7496     if (conf_get_int(ssh->conf, CONF_ssh_show_banner) &&\r
7497         bufchain_size(&ssh->banner) <= 131072) {\r
7498         char *banner = NULL;\r
7499         int size = 0;\r
7500         ssh_pkt_getstring(pktin, &banner, &size);\r
7501         if (banner)\r
7502             bufchain_add(&ssh->banner, banner, size);\r
7503     }\r
7506 /* Helper function to deal with sending tty modes for "pty-req" */\r
7507 static void ssh2_send_ttymode(void *data, char *mode, char *val)\r
7509     struct Packet *pktout = (struct Packet *)data;\r
7510     int i = 0;\r
7511     unsigned int arg = 0;\r
7512     while (strcmp(mode, ssh_ttymodes[i].mode) != 0) i++;\r
7513     if (i == lenof(ssh_ttymodes)) return;\r
7514     switch (ssh_ttymodes[i].type) {\r
7515       case TTY_OP_CHAR:\r
7516         arg = ssh_tty_parse_specchar(val);\r
7517         break;\r
7518       case TTY_OP_BOOL:\r
7519         arg = ssh_tty_parse_boolean(val);\r
7520         break;\r
7521     }\r
7522     ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode);\r
7523     ssh2_pkt_adduint32(pktout, arg);\r
7526 static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin,\r
7527                            void *ctx)\r
7529     struct ssh2_setup_x11_state {\r
7530         int crLine;\r
7531     };\r
7532     Ssh ssh = c->ssh;\r
7533     struct Packet *pktout;\r
7534     crStateP(ssh2_setup_x11_state, ctx);\r
7536     crBeginState;\r
7538     logevent("Requesting X11 forwarding");\r
7539     pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req",\r
7540                                ssh2_setup_x11, s);\r
7541     ssh2_pkt_addbool(pktout, 0);               /* many connections */\r
7542     ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname);\r
7543     /*\r
7544      * Note that while we blank the X authentication data here, we don't\r
7545      * take any special action to blank the start of an X11 channel,\r
7546      * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection\r
7547      * without having session blanking enabled is likely to leak your\r
7548      * cookie into the log.\r
7549      */\r
7550     dont_log_password(ssh, pktout, PKTLOG_BLANK);\r
7551     ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthdatastring);\r
7552     end_log_omission(ssh, pktout);\r
7553     ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum);\r
7554     ssh2_pkt_send(ssh, pktout);\r
7556     /* Wait to be called back with either a response packet, or NULL\r
7557      * meaning clean up and free our data */\r
7558     crReturnV;\r
7560     if (pktin) {\r
7561         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
7562             logevent("X11 forwarding enabled");\r
7563             ssh->X11_fwd_enabled = TRUE;\r
7564         } else\r
7565             logevent("X11 forwarding refused");\r
7566     }\r
7568     crFinishFreeV;\r
7571 static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin,\r
7572                                    void *ctx)\r
7574     struct ssh2_setup_agent_state {\r
7575         int crLine;\r
7576     };\r
7577     Ssh ssh = c->ssh;\r
7578     struct Packet *pktout;\r
7579     crStateP(ssh2_setup_agent_state, ctx);\r
7581     crBeginState;\r
7583     logevent("Requesting OpenSSH-style agent forwarding");\r
7584     pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com",\r
7585                                ssh2_setup_agent, s);\r
7586     ssh2_pkt_send(ssh, pktout);\r
7588     /* Wait to be called back with either a response packet, or NULL\r
7589      * meaning clean up and free our data */\r
7590     crReturnV;\r
7592     if (pktin) {\r
7593         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
7594             logevent("Agent forwarding enabled");\r
7595             ssh->agentfwd_enabled = TRUE;\r
7596         } else\r
7597             logevent("Agent forwarding refused");\r
7598     }\r
7600     crFinishFreeV;\r
7603 static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin,\r
7604                                  void *ctx)\r
7606     struct ssh2_setup_pty_state {\r
7607         int crLine;\r
7608     };\r
7609     Ssh ssh = c->ssh;\r
7610     struct Packet *pktout;\r
7611     crStateP(ssh2_setup_pty_state, ctx);\r
7613     crBeginState;\r
7615     /* Unpick the terminal-speed string. */\r
7616     /* XXX perhaps we should allow no speeds to be sent. */\r
7617     ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
7618     sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
7619     /* Build the pty request. */\r
7620     pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req",\r
7621                                ssh2_setup_pty, s);\r
7622     ssh2_pkt_addstring(pktout, conf_get_str(ssh->conf, CONF_termtype));\r
7623     ssh2_pkt_adduint32(pktout, ssh->term_width);\r
7624     ssh2_pkt_adduint32(pktout, ssh->term_height);\r
7625     ssh2_pkt_adduint32(pktout, 0);             /* pixel width */\r
7626     ssh2_pkt_adduint32(pktout, 0);             /* pixel height */\r
7627     ssh2_pkt_addstring_start(pktout);\r
7628     parse_ttymodes(ssh, ssh2_send_ttymode, (void *)pktout);\r
7629     ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_ISPEED);\r
7630     ssh2_pkt_adduint32(pktout, ssh->ispeed);\r
7631     ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_OSPEED);\r
7632     ssh2_pkt_adduint32(pktout, ssh->ospeed);\r
7633     ssh2_pkt_addstring_data(pktout, "\0", 1); /* TTY_OP_END */\r
7634     ssh2_pkt_send(ssh, pktout);\r
7635     ssh->state = SSH_STATE_INTERMED;\r
7637     /* Wait to be called back with either a response packet, or NULL\r
7638      * meaning clean up and free our data */\r
7639     crReturnV;\r
7641     if (pktin) {\r
7642         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
7643             logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
7644                       ssh->ospeed, ssh->ispeed);\r
7645             ssh->got_pty = TRUE;\r
7646         } else {\r
7647             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
7648             ssh->editing = ssh->echoing = 1;\r
7649         }\r
7650     }\r
7652     crFinishFreeV;\r
7655 static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,\r
7656                            void *ctx)\r
7658     struct ssh2_setup_env_state {\r
7659         int crLine;\r
7660         int num_env, env_left, env_ok;\r
7661     };\r
7662     Ssh ssh = c->ssh;\r
7663     struct Packet *pktout;\r
7664     crStateP(ssh2_setup_env_state, ctx);\r
7666     crBeginState;\r
7668     /*\r
7669      * Send environment variables.\r
7670      * \r
7671      * Simplest thing here is to send all the requests at once, and\r
7672      * then wait for a whole bunch of successes or failures.\r
7673      */\r
7674     s->num_env = 0;\r
7675     {\r
7676         char *key, *val;\r
7678         for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key);\r
7679              val != NULL;\r
7680              val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) {\r
7681             pktout = ssh2_chanreq_init(ssh->mainchan, "env", ssh2_setup_env, s);\r
7682             ssh2_pkt_addstring(pktout, key);\r
7683             ssh2_pkt_addstring(pktout, val);\r
7684             ssh2_pkt_send(ssh, pktout);\r
7686             s->num_env++;\r
7687         }\r
7688         if (s->num_env)\r
7689             logeventf(ssh, "Sent %d environment variables", s->num_env);\r
7690     }\r
7692     if (s->num_env) {\r
7693         s->env_ok = 0;\r
7694         s->env_left = s->num_env;\r
7696         while (s->env_left > 0) {\r
7697             /* Wait to be called back with either a response packet,\r
7698              * or NULL meaning clean up and free our data */\r
7699             crReturnV;\r
7700             if (!pktin) goto out;\r
7701             if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS)\r
7702                 s->env_ok++;\r
7703             s->env_left--;\r
7704         }\r
7706         if (s->env_ok == s->num_env) {\r
7707             logevent("All environment variables successfully set");\r
7708         } else if (s->env_ok == 0) {\r
7709             logevent("All environment variables refused");\r
7710             c_write_str(ssh, "Server refused to set environment variables\r\n");\r
7711         } else {\r
7712             logeventf(ssh, "%d environment variables refused",\r
7713                       s->num_env - s->env_ok);\r
7714             c_write_str(ssh, "Server refused to set all environment variables\r\n");\r
7715         }\r
7716     }\r
7717   out:;\r
7718     crFinishFreeV;\r
7721 /*\r
7722  * Handle the SSH-2 userauth and connection layers.\r
7723  */\r
7724 static void ssh2_msg_authconn(Ssh ssh, struct Packet *pktin)\r
7726     do_ssh2_authconn(ssh, NULL, 0, pktin);\r
7729 static void ssh2_response_authconn(struct ssh_channel *c, struct Packet *pktin,\r
7730                                    void *ctx)\r
7732     do_ssh2_authconn(c->ssh, NULL, 0, pktin);\r
7735 static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,\r
7736                              struct Packet *pktin)\r
7738     struct do_ssh2_authconn_state {\r
7739         int crLine;\r
7740         enum {\r
7741             AUTH_TYPE_NONE,\r
7742                 AUTH_TYPE_PUBLICKEY,\r
7743                 AUTH_TYPE_PUBLICKEY_OFFER_LOUD,\r
7744                 AUTH_TYPE_PUBLICKEY_OFFER_QUIET,\r
7745                 AUTH_TYPE_PASSWORD,\r
7746                 AUTH_TYPE_GSSAPI,      /* always QUIET */\r
7747                 AUTH_TYPE_KEYBOARD_INTERACTIVE,\r
7748                 AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET\r
7749         } type;\r
7750         int done_service_req;\r
7751         int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;\r
7752         int tried_pubkey_config, done_agent;\r
7753 #ifndef NO_GSSAPI\r
7754         int can_gssapi;\r
7755         int tried_gssapi;\r
7756 #endif\r
7757         int kbd_inter_refused;\r
7758         int we_are_in, userauth_success;\r
7759         prompts_t *cur_prompt;\r
7760         int num_prompts;\r
7761         char *username;\r
7762         char *password;\r
7763         int got_username;\r
7764         void *publickey_blob;\r
7765         int publickey_bloblen;\r
7766         int publickey_encrypted;\r
7767         char *publickey_algorithm;\r
7768         char *publickey_comment;\r
7769         unsigned char agent_request[5], *agent_response, *agentp;\r
7770         int agent_responselen;\r
7771         unsigned char *pkblob_in_agent;\r
7772         int keyi, nkeys;\r
7773         char *pkblob, *alg, *commentp;\r
7774         int pklen, alglen, commentlen;\r
7775         int siglen, retlen, len;\r
7776         char *q, *agentreq, *ret;\r
7777         int try_send;\r
7778         struct Packet *pktout;\r
7779         Filename *keyfile;\r
7780 #ifndef NO_GSSAPI\r
7781         struct ssh_gss_library *gsslib;\r
7782         Ssh_gss_ctx gss_ctx;\r
7783         Ssh_gss_buf gss_buf;\r
7784         Ssh_gss_buf gss_rcvtok, gss_sndtok;\r
7785         Ssh_gss_name gss_srv_name;\r
7786         Ssh_gss_stat gss_stat;\r
7787 #endif\r
7788     };\r
7789     crState(do_ssh2_authconn_state);\r
7791     crBeginState;\r
7793     /* Register as a handler for all the messages this coroutine handles. */\r
7794     ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_authconn;\r
7795     ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_authconn;\r
7796     ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_authconn;\r
7797     ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_authconn;\r
7798     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_authconn;\r
7799     ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_authconn;\r
7800     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_authconn; duplicate case value */\r
7801     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_authconn; duplicate case value */\r
7802     ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_authconn;\r
7803     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_authconn;\r
7804     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_authconn;\r
7805     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_authconn;\r
7806     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_authconn;\r
7807     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_authconn;\r
7808     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_authconn;\r
7809     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_authconn;\r
7810     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_authconn;\r
7811     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_authconn;\r
7812     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_authconn;\r
7813     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_authconn;\r
7814     \r
7815     s->done_service_req = FALSE;\r
7816     s->we_are_in = s->userauth_success = FALSE;\r
7817 #ifndef NO_GSSAPI\r
7818     s->tried_gssapi = FALSE;\r
7819 #endif\r
7821     if (!conf_get_int(ssh->conf, CONF_ssh_no_userauth)) {\r
7822         /*\r
7823          * Request userauth protocol, and await a response to it.\r
7824          */\r
7825         s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
7826         ssh2_pkt_addstring(s->pktout, "ssh-userauth");\r
7827         ssh2_pkt_send(ssh, s->pktout);\r
7828         crWaitUntilV(pktin);\r
7829         if (pktin->type == SSH2_MSG_SERVICE_ACCEPT)\r
7830             s->done_service_req = TRUE;\r
7831     }\r
7832     if (!s->done_service_req) {\r
7833         /*\r
7834          * Request connection protocol directly, without authentication.\r
7835          */\r
7836         s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
7837         ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
7838         ssh2_pkt_send(ssh, s->pktout);\r
7839         crWaitUntilV(pktin);\r
7840         if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {\r
7841             s->we_are_in = TRUE; /* no auth required */\r
7842         } else {\r
7843             bombout(("Server refused service request"));\r
7844             crStopV;\r
7845         }\r
7846     }\r
7848     /* Arrange to be able to deal with any BANNERs that come in.\r
7849      * (We do this now as packets may come in during the next bit.) */\r
7850     bufchain_init(&ssh->banner);\r
7851     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] =\r
7852         ssh2_msg_userauth_banner;\r
7854     /*\r
7855      * Misc one-time setup for authentication.\r
7856      */\r
7857     s->publickey_blob = NULL;\r
7858     if (!s->we_are_in) {\r
7860         /*\r
7861          * Load the public half of any configured public key file\r
7862          * for later use.\r
7863          */\r
7864         s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
7865         if (!filename_is_null(s->keyfile)) {\r
7866             int keytype;\r
7867             logeventf(ssh, "Reading private key file \"%.150s\"",\r
7868                       filename_to_str(s->keyfile));\r
7869             keytype = key_type(s->keyfile);\r
7870             if (keytype == SSH_KEYTYPE_SSH2) {\r
7871                 const char *error;\r
7872                 s->publickey_blob =\r
7873                     ssh2_userkey_loadpub(s->keyfile,\r
7874                                          &s->publickey_algorithm,\r
7875                                          &s->publickey_bloblen, \r
7876                                          &s->publickey_comment, &error);\r
7877                 if (s->publickey_blob) {\r
7878                     s->publickey_encrypted =\r
7879                         ssh2_userkey_encrypted(s->keyfile, NULL);\r
7880                 } else {\r
7881                     char *msgbuf;\r
7882                     logeventf(ssh, "Unable to load private key (%s)", \r
7883                               error);\r
7884                     msgbuf = dupprintf("Unable to load private key file "\r
7885                                        "\"%.150s\" (%s)\r\n",\r
7886                                        filename_to_str(s->keyfile),\r
7887                                        error);\r
7888                     c_write_str(ssh, msgbuf);\r
7889                     sfree(msgbuf);\r
7890                 }\r
7891             } else {\r
7892                 char *msgbuf;\r
7893                 logeventf(ssh, "Unable to use this key file (%s)",\r
7894                           key_type_to_str(keytype));\r
7895                 msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
7896                                    " (%s)\r\n",\r
7897                                    filename_to_str(s->keyfile),\r
7898                                    key_type_to_str(keytype));\r
7899                 c_write_str(ssh, msgbuf);\r
7900                 sfree(msgbuf);\r
7901                 s->publickey_blob = NULL;\r
7902             }\r
7903         }\r
7905         /*\r
7906          * Find out about any keys Pageant has (but if there's a\r
7907          * public key configured, filter out all others).\r
7908          */\r
7909         s->nkeys = 0;\r
7910         s->agent_response = NULL;\r
7911         s->pkblob_in_agent = NULL;\r
7912         if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists()) {\r
7914             void *r;\r
7916             logevent("Pageant is running. Requesting keys.");\r
7918             /* Request the keys held by the agent. */\r
7919             PUT_32BIT(s->agent_request, 1);\r
7920             s->agent_request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;\r
7921             if (!agent_query(s->agent_request, 5, &r, &s->agent_responselen,\r
7922                              ssh_agent_callback, ssh)) {\r
7923                 do {\r
7924                     crReturnV;\r
7925                     if (pktin) {\r
7926                         bombout(("Unexpected data from server while"\r
7927                                  " waiting for agent response"));\r
7928                         crStopV;\r
7929                     }\r
7930                 } while (pktin || inlen > 0);\r
7931                 r = ssh->agent_response;\r
7932                 s->agent_responselen = ssh->agent_response_len;\r
7933             }\r
7934             s->agent_response = (unsigned char *) r;\r
7935             if (s->agent_response && s->agent_responselen >= 5 &&\r
7936                 s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {\r
7937                 int keyi;\r
7938                 unsigned char *p;\r
7939                 p = s->agent_response + 5;\r
7940                 s->nkeys = toint(GET_32BIT(p));\r
7942                 /*\r
7943                  * Vet the Pageant response to ensure that the key\r
7944                  * count and blob lengths make sense.\r
7945                  */\r
7946                 if (s->nkeys < 0) {\r
7947                     logeventf(ssh, "Pageant response contained a negative"\r
7948                               " key count %d", s->nkeys);\r
7949                     s->nkeys = 0;\r
7950                     goto done_agent_query;\r
7951                 } else {\r
7952                     unsigned char *q = p + 4;\r
7953                     int lenleft = s->agent_responselen - 5 - 4;\r
7955                     for (keyi = 0; keyi < s->nkeys; keyi++) {\r
7956                         int bloblen, commentlen;\r
7957                         if (lenleft < 4) {\r
7958                             logeventf(ssh, "Pageant response was truncated");\r
7959                             s->nkeys = 0;\r
7960                             goto done_agent_query;\r
7961                         }\r
7962                         bloblen = toint(GET_32BIT(q));\r
7963                         if (bloblen < 0 || bloblen > lenleft) {\r
7964                             logeventf(ssh, "Pageant response was truncated");\r
7965                             s->nkeys = 0;\r
7966                             goto done_agent_query;\r
7967                         }\r
7968                         lenleft -= 4 + bloblen;\r
7969                         q += 4 + bloblen;\r
7970                         commentlen = toint(GET_32BIT(q));\r
7971                         if (commentlen < 0 || commentlen > lenleft) {\r
7972                             logeventf(ssh, "Pageant response was truncated");\r
7973                             s->nkeys = 0;\r
7974                             goto done_agent_query;\r
7975                         }\r
7976                         lenleft -= 4 + commentlen;\r
7977                         q += 4 + commentlen;\r
7978                     }\r
7979                 }\r
7981                 p += 4;\r
7982                 logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys);\r
7983                 if (s->publickey_blob) {\r
7984                     /* See if configured key is in agent. */\r
7985                     for (keyi = 0; keyi < s->nkeys; keyi++) {\r
7986                         s->pklen = toint(GET_32BIT(p));\r
7987                         if (s->pklen == s->publickey_bloblen &&\r
7988                             !memcmp(p+4, s->publickey_blob,\r
7989                                     s->publickey_bloblen)) {\r
7990                             logeventf(ssh, "Pageant key #%d matches "\r
7991                                       "configured key file", keyi);\r
7992                             s->keyi = keyi;\r
7993                             s->pkblob_in_agent = p;\r
7994                             break;\r
7995                         }\r
7996                         p += 4 + s->pklen;\r
7997                         p += toint(GET_32BIT(p)) + 4; /* comment */\r
7998                     }\r
7999                     if (!s->pkblob_in_agent) {\r
8000                         logevent("Configured key file not in Pageant");\r
8001                         s->nkeys = 0;\r
8002                     }\r
8003                 }\r
8004             } else {\r
8005                 logevent("Failed to get reply from Pageant");\r
8006             }\r
8007           done_agent_query:;\r
8008         }\r
8010     }\r
8012     /*\r
8013      * We repeat this whole loop, including the username prompt,\r
8014      * until we manage a successful authentication. If the user\r
8015      * types the wrong _password_, they can be sent back to the\r
8016      * beginning to try another username, if this is configured on.\r
8017      * (If they specify a username in the config, they are never\r
8018      * asked, even if they do give a wrong password.)\r
8019      * \r
8020      * I think this best serves the needs of\r
8021      * \r
8022      *  - the people who have no configuration, no keys, and just\r
8023      *    want to try repeated (username,password) pairs until they\r
8024      *    type both correctly\r
8025      * \r
8026      *  - people who have keys and configuration but occasionally\r
8027      *    need to fall back to passwords\r
8028      * \r
8029      *  - people with a key held in Pageant, who might not have\r
8030      *    logged in to a particular machine before; so they want to\r
8031      *    type a username, and then _either_ their key will be\r
8032      *    accepted, _or_ they will type a password. If they mistype\r
8033      *    the username they will want to be able to get back and\r
8034      *    retype it!\r
8035      */\r
8036     s->got_username = FALSE;\r
8037     while (!s->we_are_in) {\r
8038         /*\r
8039          * Get a username.\r
8040          */\r
8041         if (s->got_username && !conf_get_int(ssh->conf, CONF_change_username)) {\r
8042             /*\r
8043              * We got a username last time round this loop, and\r
8044              * with change_username turned off we don't try to get\r
8045              * it again.\r
8046              */\r
8047         } else if ((ssh->username = get_remote_username(ssh->conf)) == NULL) {\r
8048             int ret; /* need not be kept over crReturn */\r
8049             s->cur_prompt = new_prompts(ssh->frontend);\r
8050             s->cur_prompt->to_server = TRUE;\r
8051             s->cur_prompt->name = dupstr("SSH login name");\r
8052             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); \r
8053             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8054             while (ret < 0) {\r
8055                 ssh->send_ok = 1;\r
8056                 crWaitUntilV(!pktin);\r
8057                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8058                 ssh->send_ok = 0;\r
8059             }\r
8060             if (!ret) {\r
8061                 /*\r
8062                  * get_userpass_input() failed to get a username.\r
8063                  * Terminate.\r
8064                  */\r
8065                 free_prompts(s->cur_prompt);\r
8066                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
8067                 crStopV;\r
8068             }\r
8069             ssh->username = dupstr(s->cur_prompt->prompts[0]->result);\r
8070             free_prompts(s->cur_prompt);\r
8071         } else {\r
8072             char *stuff;\r
8073             if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {\r
8074                 stuff = dupprintf("Using username \"%s\".\r\n", ssh->username);\r
8075                 c_write_str(ssh, stuff);\r
8076                 sfree(stuff);\r
8077             }\r
8078         }\r
8079         s->got_username = TRUE;\r
8081         /*\r
8082          * Send an authentication request using method "none": (a)\r
8083          * just in case it succeeds, and (b) so that we know what\r
8084          * authentication methods we can usefully try next.\r
8085          */\r
8086         ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
8088         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8089         ssh2_pkt_addstring(s->pktout, ssh->username);\r
8090         ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */\r
8091         ssh2_pkt_addstring(s->pktout, "none");    /* method */\r
8092         ssh2_pkt_send(ssh, s->pktout);\r
8093         s->type = AUTH_TYPE_NONE;\r
8094         s->gotit = FALSE;\r
8095         s->we_are_in = FALSE;\r
8097         s->tried_pubkey_config = FALSE;\r
8098         s->kbd_inter_refused = FALSE;\r
8100         /* Reset agent request state. */\r
8101         s->done_agent = FALSE;\r
8102         if (s->agent_response) {\r
8103             if (s->pkblob_in_agent) {\r
8104                 s->agentp = s->pkblob_in_agent;\r
8105             } else {\r
8106                 s->agentp = s->agent_response + 5 + 4;\r
8107                 s->keyi = 0;\r
8108             }\r
8109         }\r
8111         while (1) {\r
8112             char *methods = NULL;\r
8113             int methlen = 0;\r
8115             /*\r
8116              * Wait for the result of the last authentication request.\r
8117              */\r
8118             if (!s->gotit)\r
8119                 crWaitUntilV(pktin);\r
8120             /*\r
8121              * Now is a convenient point to spew any banner material\r
8122              * that we've accumulated. (This should ensure that when\r
8123              * we exit the auth loop, we haven't any left to deal\r
8124              * with.)\r
8125              */\r
8126             {\r
8127                 int size = bufchain_size(&ssh->banner);\r
8128                 /*\r
8129                  * Don't show the banner if we're operating in\r
8130                  * non-verbose non-interactive mode. (It's probably\r
8131                  * a script, which means nobody will read the\r
8132                  * banner _anyway_, and moreover the printing of\r
8133                  * the banner will screw up processing on the\r
8134                  * output of (say) plink.)\r
8135                  */\r
8136                 if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {\r
8137                     char *banner = snewn(size, char);\r
8138                     bufchain_fetch(&ssh->banner, banner, size);\r
8139                     c_write_untrusted(ssh, banner, size);\r
8140                     sfree(banner);\r
8141                 }\r
8142                 bufchain_clear(&ssh->banner);\r
8143             }\r
8144             if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {\r
8145                 logevent("Access granted");\r
8146                 s->we_are_in = s->userauth_success = TRUE;\r
8147                 break;\r
8148             }\r
8150             if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) {\r
8151                 bombout(("Strange packet received during authentication: "\r
8152                          "type %d", pktin->type));\r
8153                 crStopV;\r
8154             }\r
8156             s->gotit = FALSE;\r
8158             /*\r
8159              * OK, we're now sitting on a USERAUTH_FAILURE message, so\r
8160              * we can look at the string in it and know what we can\r
8161              * helpfully try next.\r
8162              */\r
8163             if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {\r
8164                 ssh_pkt_getstring(pktin, &methods, &methlen);\r
8165                 if (!ssh2_pkt_getbool(pktin)) {\r
8166                     /*\r
8167                      * We have received an unequivocal Access\r
8168                      * Denied. This can translate to a variety of\r
8169                      * messages, or no message at all.\r
8170                      *\r
8171                      * For forms of authentication which are attempted\r
8172                      * implicitly, by which I mean without printing\r
8173                      * anything in the window indicating that we're\r
8174                      * trying them, we should never print 'Access\r
8175                      * denied'.\r
8176                      *\r
8177                      * If we do print a message saying that we're\r
8178                      * attempting some kind of authentication, it's OK\r
8179                      * to print a followup message saying it failed -\r
8180                      * but the message may sometimes be more specific\r
8181                      * than simply 'Access denied'.\r
8182                      *\r
8183                      * Additionally, if we'd just tried password\r
8184                      * authentication, we should break out of this\r
8185                      * whole loop so as to go back to the username\r
8186                      * prompt (iff we're configured to allow\r
8187                      * username change attempts).\r
8188                      */\r
8189                     if (s->type == AUTH_TYPE_NONE) {\r
8190                         /* do nothing */\r
8191                     } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||\r
8192                                s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {\r
8193                         if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)\r
8194                             c_write_str(ssh, "Server refused our key\r\n");\r
8195                         logevent("Server refused our key");\r
8196                     } else if (s->type == AUTH_TYPE_PUBLICKEY) {\r
8197                         /* This _shouldn't_ happen except by a\r
8198                          * protocol bug causing client and server to\r
8199                          * disagree on what is a correct signature. */\r
8200                         c_write_str(ssh, "Server refused public-key signature"\r
8201                                     " despite accepting key!\r\n");\r
8202                         logevent("Server refused public-key signature"\r
8203                                  " despite accepting key!");\r
8204                     } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {\r
8205                         /* quiet, so no c_write */\r
8206                         logevent("Server refused keyboard-interactive authentication");\r
8207                     } else if (s->type==AUTH_TYPE_GSSAPI) {\r
8208                         /* always quiet, so no c_write */\r
8209                         /* also, the code down in the GSSAPI block has\r
8210                          * already logged this in the Event Log */\r
8211                     } else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) {\r
8212                         logevent("Keyboard-interactive authentication failed");\r
8213                         c_write_str(ssh, "Access denied\r\n");\r
8214                     } else {\r
8215                         assert(s->type == AUTH_TYPE_PASSWORD);\r
8216                         logevent("Password authentication failed");\r
8217                         c_write_str(ssh, "Access denied\r\n");\r
8219                         if (conf_get_int(ssh->conf, CONF_change_username)) {\r
8220                             /* XXX perhaps we should allow\r
8221                              * keyboard-interactive to do this too? */\r
8222                             s->we_are_in = FALSE;\r
8223                             break;\r
8224                         }\r
8225                     }\r
8226                 } else {\r
8227                     c_write_str(ssh, "Further authentication required\r\n");\r
8228                     logevent("Further authentication required");\r
8229                 }\r
8231                 s->can_pubkey =\r
8232                     in_commasep_string("publickey", methods, methlen);\r
8233                 s->can_passwd =\r
8234                     in_commasep_string("password", methods, methlen);\r
8235                 s->can_keyb_inter = conf_get_int(ssh->conf, CONF_try_ki_auth) &&\r
8236                     in_commasep_string("keyboard-interactive", methods, methlen);\r
8237 #ifndef NO_GSSAPI\r
8238                 if (!ssh->gsslibs)\r
8239                     ssh->gsslibs = ssh_gss_setup(ssh->conf);\r
8240                 s->can_gssapi = conf_get_int(ssh->conf, CONF_try_gssapi_auth) &&\r
8241                     in_commasep_string("gssapi-with-mic", methods, methlen) &&\r
8242                     ssh->gsslibs->nlibraries > 0;\r
8243 #endif\r
8244             }\r
8246             ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
8248             if (s->can_pubkey && !s->done_agent && s->nkeys) {\r
8250                 /*\r
8251                  * Attempt public-key authentication using a key from Pageant.\r
8252                  */\r
8254                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
8256                 logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
8258                 /* Unpack key from agent response */\r
8259                 s->pklen = toint(GET_32BIT(s->agentp));\r
8260                 s->agentp += 4;\r
8261                 s->pkblob = (char *)s->agentp;\r
8262                 s->agentp += s->pklen;\r
8263                 s->alglen = toint(GET_32BIT(s->pkblob));\r
8264                 s->alg = s->pkblob + 4;\r
8265                 s->commentlen = toint(GET_32BIT(s->agentp));\r
8266                 s->agentp += 4;\r
8267                 s->commentp = (char *)s->agentp;\r
8268                 s->agentp += s->commentlen;\r
8269                 /* s->agentp now points at next key, if any */\r
8271                 /* See if server will accept it */\r
8272                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8273                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
8274                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8275                                                     /* service requested */\r
8276                 ssh2_pkt_addstring(s->pktout, "publickey");\r
8277                                                     /* method */\r
8278                 ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */\r
8279                 ssh2_pkt_addstring_start(s->pktout);\r
8280                 ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
8281                 ssh2_pkt_addstring_start(s->pktout);\r
8282                 ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
8283                 ssh2_pkt_send(ssh, s->pktout);\r
8284                 s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;\r
8286                 crWaitUntilV(pktin);\r
8287                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
8289                     /* Offer of key refused. */\r
8290                     s->gotit = TRUE;\r
8292                 } else {\r
8293                     \r
8294                     void *vret;\r
8296                     if (flags & FLAG_VERBOSE) {\r
8297                         c_write_str(ssh, "Authenticating with "\r
8298                                     "public key \"");\r
8299                         c_write(ssh, s->commentp, s->commentlen);\r
8300                         c_write_str(ssh, "\" from agent\r\n");\r
8301                     }\r
8303                     /*\r
8304                      * Server is willing to accept the key.\r
8305                      * Construct a SIGN_REQUEST.\r
8306                      */\r
8307                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8308                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
8309                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8310                                                         /* service requested */\r
8311                     ssh2_pkt_addstring(s->pktout, "publickey");\r
8312                                                         /* method */\r
8313                     ssh2_pkt_addbool(s->pktout, TRUE);  /* signature included */\r
8314                     ssh2_pkt_addstring_start(s->pktout);\r
8315                     ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
8316                     ssh2_pkt_addstring_start(s->pktout);\r
8317                     ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
8319                     /* Ask agent for signature. */\r
8320                     s->siglen = s->pktout->length - 5 + 4 +\r
8321                         ssh->v2_session_id_len;\r
8322                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
8323                         s->siglen -= 4;\r
8324                     s->len = 1;       /* message type */\r
8325                     s->len += 4 + s->pklen;     /* key blob */\r
8326                     s->len += 4 + s->siglen;    /* data to sign */\r
8327                     s->len += 4;      /* flags */\r
8328                     s->agentreq = snewn(4 + s->len, char);\r
8329                     PUT_32BIT(s->agentreq, s->len);\r
8330                     s->q = s->agentreq + 4;\r
8331                     *s->q++ = SSH2_AGENTC_SIGN_REQUEST;\r
8332                     PUT_32BIT(s->q, s->pklen);\r
8333                     s->q += 4;\r
8334                     memcpy(s->q, s->pkblob, s->pklen);\r
8335                     s->q += s->pklen;\r
8336                     PUT_32BIT(s->q, s->siglen);\r
8337                     s->q += 4;\r
8338                     /* Now the data to be signed... */\r
8339                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
8340                         PUT_32BIT(s->q, ssh->v2_session_id_len);\r
8341                         s->q += 4;\r
8342                     }\r
8343                     memcpy(s->q, ssh->v2_session_id,\r
8344                            ssh->v2_session_id_len);\r
8345                     s->q += ssh->v2_session_id_len;\r
8346                     memcpy(s->q, s->pktout->data + 5,\r
8347                            s->pktout->length - 5);\r
8348                     s->q += s->pktout->length - 5;\r
8349                     /* And finally the (zero) flags word. */\r
8350                     PUT_32BIT(s->q, 0);\r
8351                     if (!agent_query(s->agentreq, s->len + 4,\r
8352                                      &vret, &s->retlen,\r
8353                                      ssh_agent_callback, ssh)) {\r
8354                         do {\r
8355                             crReturnV;\r
8356                             if (pktin) {\r
8357                                 bombout(("Unexpected data from server"\r
8358                                          " while waiting for agent"\r
8359                                          " response"));\r
8360                                 crStopV;\r
8361                             }\r
8362                         } while (pktin || inlen > 0);\r
8363                         vret = ssh->agent_response;\r
8364                         s->retlen = ssh->agent_response_len;\r
8365                     }\r
8366                     s->ret = vret;\r
8367                     sfree(s->agentreq);\r
8368                     if (s->ret) {\r
8369                         if (s->retlen >= 9 &&\r
8370                             s->ret[4] == SSH2_AGENT_SIGN_RESPONSE &&\r
8371                             GET_32BIT(s->ret + 5) <= (unsigned)(s->retlen-9)) {\r
8372                             logevent("Sending Pageant's response");\r
8373                             ssh2_add_sigblob(ssh, s->pktout,\r
8374                                              s->pkblob, s->pklen,\r
8375                                              s->ret + 9,\r
8376                                              GET_32BIT(s->ret + 5));\r
8377                             ssh2_pkt_send(ssh, s->pktout);\r
8378                             s->type = AUTH_TYPE_PUBLICKEY;\r
8379                         } else {\r
8380                             /* FIXME: less drastic response */\r
8381                             bombout(("Pageant failed to answer challenge"));\r
8382                             crStopV;\r
8383                         }\r
8384                     }\r
8385                 }\r
8387                 /* Do we have any keys left to try? */\r
8388                 if (s->pkblob_in_agent) {\r
8389                     s->done_agent = TRUE;\r
8390                     s->tried_pubkey_config = TRUE;\r
8391                 } else {\r
8392                     s->keyi++;\r
8393                     if (s->keyi >= s->nkeys)\r
8394                         s->done_agent = TRUE;\r
8395                 }\r
8397             } else if (s->can_pubkey && s->publickey_blob &&\r
8398                        !s->tried_pubkey_config) {\r
8400                 struct ssh2_userkey *key;   /* not live over crReturn */\r
8401                 char *passphrase;           /* not live over crReturn */\r
8403                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
8405                 s->tried_pubkey_config = TRUE;\r
8407                 /*\r
8408                  * Try the public key supplied in the configuration.\r
8409                  *\r
8410                  * First, offer the public blob to see if the server is\r
8411                  * willing to accept it.\r
8412                  */\r
8413                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8414                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
8415                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8416                                                 /* service requested */\r
8417                 ssh2_pkt_addstring(s->pktout, "publickey");     /* method */\r
8418                 ssh2_pkt_addbool(s->pktout, FALSE);\r
8419                                                 /* no signature included */\r
8420                 ssh2_pkt_addstring(s->pktout, s->publickey_algorithm);\r
8421                 ssh2_pkt_addstring_start(s->pktout);\r
8422                 ssh2_pkt_addstring_data(s->pktout,\r
8423                                         (char *)s->publickey_blob,\r
8424                                         s->publickey_bloblen);\r
8425                 ssh2_pkt_send(ssh, s->pktout);\r
8426                 logevent("Offered public key");\r
8428                 crWaitUntilV(pktin);\r
8429                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
8430                     /* Key refused. Give up. */\r
8431                     s->gotit = TRUE; /* reconsider message next loop */\r
8432                     s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;\r
8433                     continue; /* process this new message */\r
8434                 }\r
8435                 logevent("Offer of public key accepted");\r
8437                 /*\r
8438                  * Actually attempt a serious authentication using\r
8439                  * the key.\r
8440                  */\r
8441                 if (flags & FLAG_VERBOSE) {\r
8442                     c_write_str(ssh, "Authenticating with public key \"");\r
8443                     c_write_str(ssh, s->publickey_comment);\r
8444                     c_write_str(ssh, "\"\r\n");\r
8445                 }\r
8446                 key = NULL;\r
8447                 while (!key) {\r
8448                     const char *error;  /* not live over crReturn */\r
8449                     if (s->publickey_encrypted) {\r
8450                         /*\r
8451                          * Get a passphrase from the user.\r
8452                          */\r
8453                         int ret; /* need not be kept over crReturn */\r
8454                         s->cur_prompt = new_prompts(ssh->frontend);\r
8455                         s->cur_prompt->to_server = FALSE;\r
8456                         s->cur_prompt->name = dupstr("SSH key passphrase");\r
8457                         add_prompt(s->cur_prompt,\r
8458                                    dupprintf("Passphrase for key \"%.100s\": ",\r
8459                                              s->publickey_comment),\r
8460                                    FALSE);\r
8461                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8462                         while (ret < 0) {\r
8463                             ssh->send_ok = 1;\r
8464                             crWaitUntilV(!pktin);\r
8465                             ret = get_userpass_input(s->cur_prompt,\r
8466                                                      in, inlen);\r
8467                             ssh->send_ok = 0;\r
8468                         }\r
8469                         if (!ret) {\r
8470                             /* Failed to get a passphrase. Terminate. */\r
8471                             free_prompts(s->cur_prompt);\r
8472                             ssh_disconnect(ssh, NULL,\r
8473                                            "Unable to authenticate",\r
8474                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8475                                            TRUE);\r
8476                             crStopV;\r
8477                         }\r
8478                         passphrase =\r
8479                             dupstr(s->cur_prompt->prompts[0]->result);\r
8480                         free_prompts(s->cur_prompt);\r
8481                     } else {\r
8482                         passphrase = NULL; /* no passphrase needed */\r
8483                     }\r
8485                     /*\r
8486                      * Try decrypting the key.\r
8487                      */\r
8488                     s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
8489                     key = ssh2_load_userkey(s->keyfile, passphrase, &error);\r
8490                     if (passphrase) {\r
8491                         /* burn the evidence */\r
8492                         smemclr(passphrase, strlen(passphrase));\r
8493                         sfree(passphrase);\r
8494                     }\r
8495                     if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {\r
8496                         if (passphrase &&\r
8497                             (key == SSH2_WRONG_PASSPHRASE)) {\r
8498                             c_write_str(ssh, "Wrong passphrase\r\n");\r
8499                             key = NULL;\r
8500                             /* and loop again */\r
8501                         } else {\r
8502                             c_write_str(ssh, "Unable to load private key (");\r
8503                             c_write_str(ssh, error);\r
8504                             c_write_str(ssh, ")\r\n");\r
8505                             key = NULL;\r
8506                             break; /* try something else */\r
8507                         }\r
8508                     }\r
8509                 }\r
8511                 if (key) {\r
8512                     unsigned char *pkblob, *sigblob, *sigdata;\r
8513                     int pkblob_len, sigblob_len, sigdata_len;\r
8514                     int p;\r
8516                     /*\r
8517                      * We have loaded the private key and the server\r
8518                      * has announced that it's willing to accept it.\r
8519                      * Hallelujah. Generate a signature and send it.\r
8520                      */\r
8521                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8522                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
8523                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8524                                                     /* service requested */\r
8525                     ssh2_pkt_addstring(s->pktout, "publickey");\r
8526                                                     /* method */\r
8527                     ssh2_pkt_addbool(s->pktout, TRUE);\r
8528                                                     /* signature follows */\r
8529                     ssh2_pkt_addstring(s->pktout, key->alg->name);\r
8530                     pkblob = key->alg->public_blob(key->data,\r
8531                                                    &pkblob_len);\r
8532                     ssh2_pkt_addstring_start(s->pktout);\r
8533                     ssh2_pkt_addstring_data(s->pktout, (char *)pkblob,\r
8534                                             pkblob_len);\r
8536                     /*\r
8537                      * The data to be signed is:\r
8538                      *\r
8539                      *   string  session-id\r
8540                      *\r
8541                      * followed by everything so far placed in the\r
8542                      * outgoing packet.\r
8543                      */\r
8544                     sigdata_len = s->pktout->length - 5 + 4 +\r
8545                         ssh->v2_session_id_len;\r
8546                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
8547                         sigdata_len -= 4;\r
8548                     sigdata = snewn(sigdata_len, unsigned char);\r
8549                     p = 0;\r
8550                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
8551                         PUT_32BIT(sigdata+p, ssh->v2_session_id_len);\r
8552                         p += 4;\r
8553                     }\r
8554                     memcpy(sigdata+p, ssh->v2_session_id,\r
8555                            ssh->v2_session_id_len);\r
8556                     p += ssh->v2_session_id_len;\r
8557                     memcpy(sigdata+p, s->pktout->data + 5,\r
8558                            s->pktout->length - 5);\r
8559                     p += s->pktout->length - 5;\r
8560                     assert(p == sigdata_len);\r
8561                     sigblob = key->alg->sign(key->data, (char *)sigdata,\r
8562                                              sigdata_len, &sigblob_len);\r
8563                     ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,\r
8564                                      sigblob, sigblob_len);\r
8565                     sfree(pkblob);\r
8566                     sfree(sigblob);\r
8567                     sfree(sigdata);\r
8569                     ssh2_pkt_send(ssh, s->pktout);\r
8570                     logevent("Sent public key signature");\r
8571                     s->type = AUTH_TYPE_PUBLICKEY;\r
8572                     key->alg->freekey(key->data);\r
8573                 }\r
8575 #ifndef NO_GSSAPI\r
8576             } else if (s->can_gssapi && !s->tried_gssapi) {\r
8578                 /* GSSAPI Authentication */\r
8580                 int micoffset, len;\r
8581                 char *data;\r
8582                 Ssh_gss_buf mic;\r
8583                 s->type = AUTH_TYPE_GSSAPI;\r
8584                 s->tried_gssapi = TRUE;\r
8585                 s->gotit = TRUE;\r
8586                 ssh->pkt_actx = SSH2_PKTCTX_GSSAPI;\r
8588                 /*\r
8589                  * Pick the highest GSS library on the preference\r
8590                  * list.\r
8591                  */\r
8592                 {\r
8593                     int i, j;\r
8594                     s->gsslib = NULL;\r
8595                     for (i = 0; i < ngsslibs; i++) {\r
8596                         int want_id = conf_get_int_int(ssh->conf,\r
8597                                                        CONF_ssh_gsslist, i);\r
8598                         for (j = 0; j < ssh->gsslibs->nlibraries; j++)\r
8599                             if (ssh->gsslibs->libraries[j].id == want_id) {\r
8600                                 s->gsslib = &ssh->gsslibs->libraries[j];\r
8601                                 goto got_gsslib;   /* double break */\r
8602                             }\r
8603                     }\r
8604                     got_gsslib:\r
8605                     /*\r
8606                      * We always expect to have found something in\r
8607                      * the above loop: we only came here if there\r
8608                      * was at least one viable GSS library, and the\r
8609                      * preference list should always mention\r
8610                      * everything and only change the order.\r
8611                      */\r
8612                     assert(s->gsslib);\r
8613                 }\r
8615                 if (s->gsslib->gsslogmsg)\r
8616                     logevent(s->gsslib->gsslogmsg);\r
8618                 /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */\r
8619                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8620                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
8621                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8622                 ssh2_pkt_addstring(s->pktout, "gssapi-with-mic");\r
8623                 logevent("Attempting GSSAPI authentication");\r
8625                 /* add mechanism info */\r
8626                 s->gsslib->indicate_mech(s->gsslib, &s->gss_buf);\r
8628                 /* number of GSSAPI mechanisms */\r
8629                 ssh2_pkt_adduint32(s->pktout,1);\r
8631                 /* length of OID + 2 */\r
8632                 ssh2_pkt_adduint32(s->pktout, s->gss_buf.length + 2);\r
8633                 ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);\r
8635                 /* length of OID */\r
8636                 ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.length);\r
8638                 ssh_pkt_adddata(s->pktout, s->gss_buf.value,\r
8639                                 s->gss_buf.length);\r
8640                 ssh2_pkt_send(ssh, s->pktout);\r
8641                 crWaitUntilV(pktin);\r
8642                 if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {\r
8643                     logevent("GSSAPI authentication request refused");\r
8644                     continue;\r
8645                 }\r
8647                 /* check returned packet ... */\r
8649                 ssh_pkt_getstring(pktin, &data, &len);\r
8650                 s->gss_rcvtok.value = data;\r
8651                 s->gss_rcvtok.length = len;\r
8652                 if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||\r
8653                     ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||\r
8654                     ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||\r
8655                     memcmp((char *)s->gss_rcvtok.value + 2,\r
8656                            s->gss_buf.value,s->gss_buf.length) ) {\r
8657                     logevent("GSSAPI authentication - wrong response from server");\r
8658                     continue;\r
8659                 }\r
8661                 /* now start running */\r
8662                 s->gss_stat = s->gsslib->import_name(s->gsslib,\r
8663                                                      ssh->fullhostname,\r
8664                                                      &s->gss_srv_name);\r
8665                 if (s->gss_stat != SSH_GSS_OK) {\r
8666                     if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)\r
8667                         logevent("GSSAPI import name failed - Bad service name");\r
8668                     else\r
8669                         logevent("GSSAPI import name failed");\r
8670                     continue;\r
8671                 }\r
8673                 /* fetch TGT into GSS engine */\r
8674                 s->gss_stat = s->gsslib->acquire_cred(s->gsslib, &s->gss_ctx);\r
8676                 if (s->gss_stat != SSH_GSS_OK) {\r
8677                     logevent("GSSAPI authentication failed to get credentials");\r
8678                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8679                     continue;\r
8680                 }\r
8682                 /* initial tokens are empty */\r
8683                 SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);\r
8684                 SSH_GSS_CLEAR_BUF(&s->gss_sndtok);\r
8686                 /* now enter the loop */\r
8687                 do {\r
8688                     s->gss_stat = s->gsslib->init_sec_context\r
8689                         (s->gsslib,\r
8690                          &s->gss_ctx,\r
8691                          s->gss_srv_name,\r
8692                          conf_get_int(ssh->conf, CONF_gssapifwd),\r
8693                          &s->gss_rcvtok,\r
8694                          &s->gss_sndtok);\r
8696                     if (s->gss_stat!=SSH_GSS_S_COMPLETE &&\r
8697                         s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) {\r
8698                         logevent("GSSAPI authentication initialisation failed");\r
8700                         if (s->gsslib->display_status(s->gsslib, s->gss_ctx,\r
8701                                                       &s->gss_buf) == SSH_GSS_OK) {\r
8702                             logevent(s->gss_buf.value);\r
8703                             sfree(s->gss_buf.value);\r
8704                         }\r
8706                         break;\r
8707                     }\r
8708                     logevent("GSSAPI authentication initialised");\r
8710                     /* Client and server now exchange tokens until GSSAPI\r
8711                      * no longer says CONTINUE_NEEDED */\r
8713                     if (s->gss_sndtok.length != 0) {\r
8714                         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);\r
8715                         ssh_pkt_addstring_start(s->pktout);\r
8716                         ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.value,s->gss_sndtok.length);\r
8717                         ssh2_pkt_send(ssh, s->pktout);\r
8718                         s->gsslib->free_tok(s->gsslib, &s->gss_sndtok);\r
8719                     }\r
8721                     if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {\r
8722                         crWaitUntilV(pktin);\r
8723                         if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {\r
8724                             logevent("GSSAPI authentication - bad server response");\r
8725                             s->gss_stat = SSH_GSS_FAILURE;\r
8726                             break;\r
8727                         }\r
8728                         ssh_pkt_getstring(pktin, &data, &len);\r
8729                         s->gss_rcvtok.value = data;\r
8730                         s->gss_rcvtok.length = len;\r
8731                     }\r
8732                 } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);\r
8734                 if (s->gss_stat != SSH_GSS_OK) {\r
8735                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8736                     s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
8737                     continue;\r
8738                 }\r
8739                 logevent("GSSAPI authentication loop finished OK");\r
8741                 /* Now send the MIC */\r
8743                 s->pktout = ssh2_pkt_init(0);\r
8744                 micoffset = s->pktout->length;\r
8745                 ssh_pkt_addstring_start(s->pktout);\r
8746                 ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len);\r
8747                 ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST);\r
8748                 ssh_pkt_addstring(s->pktout, ssh->username);\r
8749                 ssh_pkt_addstring(s->pktout, "ssh-connection");\r
8750                 ssh_pkt_addstring(s->pktout, "gssapi-with-mic");\r
8752                 s->gss_buf.value = (char *)s->pktout->data + micoffset;\r
8753                 s->gss_buf.length = s->pktout->length - micoffset;\r
8755                 s->gsslib->get_mic(s->gsslib, s->gss_ctx, &s->gss_buf, &mic);\r
8756                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC);\r
8757                 ssh_pkt_addstring_start(s->pktout);\r
8758                 ssh_pkt_addstring_data(s->pktout, mic.value, mic.length);\r
8759                 ssh2_pkt_send(ssh, s->pktout);\r
8760                 s->gsslib->free_mic(s->gsslib, &mic);\r
8762                 s->gotit = FALSE;\r
8764                 s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8765                 s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
8766                 continue;\r
8767 #endif\r
8768             } else if (s->can_keyb_inter && !s->kbd_inter_refused) {\r
8770                 /*\r
8771                  * Keyboard-interactive authentication.\r
8772                  */\r
8774                 s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;\r
8776                 ssh->pkt_actx = SSH2_PKTCTX_KBDINTER;\r
8778                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8779                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
8780                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8781                                                         /* service requested */\r
8782                 ssh2_pkt_addstring(s->pktout, "keyboard-interactive");\r
8783                                                         /* method */\r
8784                 ssh2_pkt_addstring(s->pktout, "");      /* lang */\r
8785                 ssh2_pkt_addstring(s->pktout, "");      /* submethods */\r
8786                 ssh2_pkt_send(ssh, s->pktout);\r
8787                 \r
8788                 logevent("Attempting keyboard-interactive authentication");\r
8790                 crWaitUntilV(pktin);\r
8791                 if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
8792                     /* Server is not willing to do keyboard-interactive\r
8793                      * at all (or, bizarrely but legally, accepts the\r
8794                      * user without actually issuing any prompts).\r
8795                      * Give up on it entirely. */\r
8796                     s->gotit = TRUE;\r
8797                     s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;\r
8798                     s->kbd_inter_refused = TRUE; /* don't try it again */\r
8799                     continue;\r
8800                 }\r
8802                 /*\r
8803                  * Loop while the server continues to send INFO_REQUESTs.\r
8804                  */\r
8805                 while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
8807                     char *name, *inst, *lang;\r
8808                     int name_len, inst_len, lang_len;\r
8809                     int i;\r
8811                     /*\r
8812                      * We've got a fresh USERAUTH_INFO_REQUEST.\r
8813                      * Get the preamble and start building a prompt.\r
8814                      */\r
8815                     ssh_pkt_getstring(pktin, &name, &name_len);\r
8816                     ssh_pkt_getstring(pktin, &inst, &inst_len);\r
8817                     ssh_pkt_getstring(pktin, &lang, &lang_len);\r
8818                     s->cur_prompt = new_prompts(ssh->frontend);\r
8819                     s->cur_prompt->to_server = TRUE;\r
8821                     /*\r
8822                      * Get any prompt(s) from the packet.\r
8823                      */\r
8824                     s->num_prompts = ssh_pkt_getuint32(pktin);\r
8825                     for (i = 0; i < s->num_prompts; i++) {\r
8826                         char *prompt;\r
8827                         int prompt_len;\r
8828                         int echo;\r
8829                         static char noprompt[] =\r
8830                             "<server failed to send prompt>: ";\r
8832                         ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
8833                         echo = ssh2_pkt_getbool(pktin);\r
8834                         if (!prompt_len) {\r
8835                             prompt = noprompt;\r
8836                             prompt_len = lenof(noprompt)-1;\r
8837                         }\r
8838                         add_prompt(s->cur_prompt,\r
8839                                    dupprintf("%.*s", prompt_len, prompt),\r
8840                                    echo);\r
8841                     }\r
8843                     if (name_len) {\r
8844                         /* FIXME: better prefix to distinguish from\r
8845                          * local prompts? */\r
8846                         s->cur_prompt->name =\r
8847                             dupprintf("SSH server: %.*s", name_len, name);\r
8848                         s->cur_prompt->name_reqd = TRUE;\r
8849                     } else {\r
8850                         s->cur_prompt->name =\r
8851                             dupstr("SSH server authentication");\r
8852                         s->cur_prompt->name_reqd = FALSE;\r
8853                     }\r
8854                     /* We add a prefix to try to make it clear that a prompt\r
8855                      * has come from the server.\r
8856                      * FIXME: ugly to print "Using..." in prompt _every_\r
8857                      * time round. Can this be done more subtly? */\r
8858                     /* Special case: for reasons best known to themselves,\r
8859                      * some servers send k-i requests with no prompts and\r
8860                      * nothing to display. Keep quiet in this case. */\r
8861                     if (s->num_prompts || name_len || inst_len) {\r
8862                         s->cur_prompt->instruction =\r
8863                             dupprintf("Using keyboard-interactive authentication.%s%.*s",\r
8864                                       inst_len ? "\n" : "", inst_len, inst);\r
8865                         s->cur_prompt->instr_reqd = TRUE;\r
8866                     } else {\r
8867                         s->cur_prompt->instr_reqd = FALSE;\r
8868                     }\r
8870                     /*\r
8871                      * Display any instructions, and get the user's\r
8872                      * response(s).\r
8873                      */\r
8874                     {\r
8875                         int ret; /* not live over crReturn */\r
8876                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8877                         while (ret < 0) {\r
8878                             ssh->send_ok = 1;\r
8879                             crWaitUntilV(!pktin);\r
8880                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8881                             ssh->send_ok = 0;\r
8882                         }\r
8883                         if (!ret) {\r
8884                             /*\r
8885                              * Failed to get responses. Terminate.\r
8886                              */\r
8887                             free_prompts(s->cur_prompt);\r
8888                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
8889                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8890                                            TRUE);\r
8891                             crStopV;\r
8892                         }\r
8893                     }\r
8895                     /*\r
8896                      * Send the response(s) to the server.\r
8897                      */\r
8898                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);\r
8899                     ssh2_pkt_adduint32(s->pktout, s->num_prompts);\r
8900                     for (i=0; i < s->num_prompts; i++) {\r
8901                         dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8902                         ssh2_pkt_addstring(s->pktout,\r
8903                                            s->cur_prompt->prompts[i]->result);\r
8904                         end_log_omission(ssh, s->pktout);\r
8905                     }\r
8906                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
8908                     /*\r
8909                      * Free the prompts structure from this iteration.\r
8910                      * If there's another, a new one will be allocated\r
8911                      * when we return to the top of this while loop.\r
8912                      */\r
8913                     free_prompts(s->cur_prompt);\r
8915                     /*\r
8916                      * Get the next packet in case it's another\r
8917                      * INFO_REQUEST.\r
8918                      */\r
8919                     crWaitUntilV(pktin);\r
8921                 }\r
8923                 /*\r
8924                  * We should have SUCCESS or FAILURE now.\r
8925                  */\r
8926                 s->gotit = TRUE;\r
8928             } else if (s->can_passwd) {\r
8930                 /*\r
8931                  * Plain old password authentication.\r
8932                  */\r
8933                 int ret; /* not live over crReturn */\r
8934                 int changereq_first_time; /* not live over crReturn */\r
8936                 ssh->pkt_actx = SSH2_PKTCTX_PASSWORD;\r
8938                 s->cur_prompt = new_prompts(ssh->frontend);\r
8939                 s->cur_prompt->to_server = TRUE;\r
8940                 s->cur_prompt->name = dupstr("SSH password");\r
8941                 add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",\r
8942                                                     ssh->username,\r
8943                                                     ssh->savedhost),\r
8944                            FALSE);\r
8946                 ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8947                 while (ret < 0) {\r
8948                     ssh->send_ok = 1;\r
8949                     crWaitUntilV(!pktin);\r
8950                     ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8951                     ssh->send_ok = 0;\r
8952                 }\r
8953                 if (!ret) {\r
8954                     /*\r
8955                      * Failed to get responses. Terminate.\r
8956                      */\r
8957                     free_prompts(s->cur_prompt);\r
8958                     ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
8959                                    SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8960                                    TRUE);\r
8961                     crStopV;\r
8962                 }\r
8963                 /*\r
8964                  * Squirrel away the password. (We may need it later if\r
8965                  * asked to change it.)\r
8966                  */\r
8967                 s->password = dupstr(s->cur_prompt->prompts[0]->result);\r
8968                 free_prompts(s->cur_prompt);\r
8970                 /*\r
8971                  * Send the password packet.\r
8972                  *\r
8973                  * We pad out the password packet to 256 bytes to make\r
8974                  * it harder for an attacker to find the length of the\r
8975                  * user's password.\r
8976                  *\r
8977                  * Anyone using a password longer than 256 bytes\r
8978                  * probably doesn't have much to worry about from\r
8979                  * people who find out how long their password is!\r
8980                  */\r
8981                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8982                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
8983                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8984                                                         /* service requested */\r
8985                 ssh2_pkt_addstring(s->pktout, "password");\r
8986                 ssh2_pkt_addbool(s->pktout, FALSE);\r
8987                 dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8988                 ssh2_pkt_addstring(s->pktout, s->password);\r
8989                 end_log_omission(ssh, s->pktout);\r
8990                 ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
8991                 logevent("Sent password");\r
8992                 s->type = AUTH_TYPE_PASSWORD;\r
8994                 /*\r
8995                  * Wait for next packet, in case it's a password change\r
8996                  * request.\r
8997                  */\r
8998                 crWaitUntilV(pktin);\r
8999                 changereq_first_time = TRUE;\r
9001                 while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {\r
9003                     /* \r
9004                      * We're being asked for a new password\r
9005                      * (perhaps not for the first time).\r
9006                      * Loop until the server accepts it.\r
9007                      */\r
9009                     int got_new = FALSE; /* not live over crReturn */\r
9010                     char *prompt;   /* not live over crReturn */\r
9011                     int prompt_len; /* not live over crReturn */\r
9012                     \r
9013                     {\r
9014                         char *msg;\r
9015                         if (changereq_first_time)\r
9016                             msg = "Server requested password change";\r
9017                         else\r
9018                             msg = "Server rejected new password";\r
9019                         logevent(msg);\r
9020                         c_write_str(ssh, msg);\r
9021                         c_write_str(ssh, "\r\n");\r
9022                     }\r
9024                     ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
9026                     s->cur_prompt = new_prompts(ssh->frontend);\r
9027                     s->cur_prompt->to_server = TRUE;\r
9028                     s->cur_prompt->name = dupstr("New SSH password");\r
9029                     s->cur_prompt->instruction =\r
9030                         dupprintf("%.*s", prompt_len, prompt);\r
9031                     s->cur_prompt->instr_reqd = TRUE;\r
9032                     /*\r
9033                      * There's no explicit requirement in the protocol\r
9034                      * for the "old" passwords in the original and\r
9035                      * password-change messages to be the same, and\r
9036                      * apparently some Cisco kit supports password change\r
9037                      * by the user entering a blank password originally\r
9038                      * and the real password subsequently, so,\r
9039                      * reluctantly, we prompt for the old password again.\r
9040                      *\r
9041                      * (On the other hand, some servers don't even bother\r
9042                      * to check this field.)\r
9043                      */\r
9044                     add_prompt(s->cur_prompt,\r
9045                                dupstr("Current password (blank for previously entered password): "),\r
9046                                FALSE);\r
9047                     add_prompt(s->cur_prompt, dupstr("Enter new password: "),\r
9048                                FALSE);\r
9049                     add_prompt(s->cur_prompt, dupstr("Confirm new password: "),\r
9050                                FALSE);\r
9052                     /*\r
9053                      * Loop until the user manages to enter the same\r
9054                      * password twice.\r
9055                      */\r
9056                     while (!got_new) {\r
9058                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
9059                         while (ret < 0) {\r
9060                             ssh->send_ok = 1;\r
9061                             crWaitUntilV(!pktin);\r
9062                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
9063                             ssh->send_ok = 0;\r
9064                         }\r
9065                         if (!ret) {\r
9066                             /*\r
9067                              * Failed to get responses. Terminate.\r
9068                              */\r
9069                             /* burn the evidence */\r
9070                             free_prompts(s->cur_prompt);\r
9071                             smemclr(s->password, strlen(s->password));\r
9072                             sfree(s->password);\r
9073                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
9074                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
9075                                            TRUE);\r
9076                             crStopV;\r
9077                         }\r
9079                         /*\r
9080                          * If the user specified a new original password\r
9081                          * (IYSWIM), overwrite any previously specified\r
9082                          * one.\r
9083                          * (A side effect is that the user doesn't have to\r
9084                          * re-enter it if they louse up the new password.)\r
9085                          */\r
9086                         if (s->cur_prompt->prompts[0]->result[0]) {\r
9087                             smemclr(s->password, strlen(s->password));\r
9088                                 /* burn the evidence */\r
9089                             sfree(s->password);\r
9090                             s->password =\r
9091                                 dupstr(s->cur_prompt->prompts[0]->result);\r
9092                         }\r
9094                         /*\r
9095                          * Check the two new passwords match.\r
9096                          */\r
9097                         got_new = (strcmp(s->cur_prompt->prompts[1]->result,\r
9098                                           s->cur_prompt->prompts[2]->result)\r
9099                                    == 0);\r
9100                         if (!got_new)\r
9101                             /* They don't. Silly user. */\r
9102                             c_write_str(ssh, "Passwords do not match\r\n");\r
9104                     }\r
9106                     /*\r
9107                      * Send the new password (along with the old one).\r
9108                      * (see above for padding rationale)\r
9109                      */\r
9110                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
9111                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
9112                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
9113                                                         /* service requested */\r
9114                     ssh2_pkt_addstring(s->pktout, "password");\r
9115                     ssh2_pkt_addbool(s->pktout, TRUE);\r
9116                     dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
9117                     ssh2_pkt_addstring(s->pktout, s->password);\r
9118                     ssh2_pkt_addstring(s->pktout,\r
9119                                        s->cur_prompt->prompts[1]->result);\r
9120                     free_prompts(s->cur_prompt);\r
9121                     end_log_omission(ssh, s->pktout);\r
9122                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
9123                     logevent("Sent new password");\r
9124                     \r
9125                     /*\r
9126                      * Now see what the server has to say about it.\r
9127                      * (If it's CHANGEREQ again, it's not happy with the\r
9128                      * new password.)\r
9129                      */\r
9130                     crWaitUntilV(pktin);\r
9131                     changereq_first_time = FALSE;\r
9133                 }\r
9135                 /*\r
9136                  * We need to reexamine the current pktin at the top\r
9137                  * of the loop. Either:\r
9138                  *  - we weren't asked to change password at all, in\r
9139                  *    which case it's a SUCCESS or FAILURE with the\r
9140                  *    usual meaning\r
9141                  *  - we sent a new password, and the server was\r
9142                  *    either OK with it (SUCCESS or FAILURE w/partial\r
9143                  *    success) or unhappy with the _old_ password\r
9144                  *    (FAILURE w/o partial success)\r
9145                  * In any of these cases, we go back to the top of\r
9146                  * the loop and start again.\r
9147                  */\r
9148                 s->gotit = TRUE;\r
9150                 /*\r
9151                  * We don't need the old password any more, in any\r
9152                  * case. Burn the evidence.\r
9153                  */\r
9154                 smemclr(s->password, strlen(s->password));\r
9155                 sfree(s->password);\r
9157             } else {\r
9158                 char *str = dupprintf("No supported authentication methods available"\r
9159                                       " (server sent: %.*s)",\r
9160                                       methlen, methods);\r
9162                 ssh_disconnect(ssh, str,\r
9163                                "No supported authentication methods available",\r
9164                                SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,\r
9165                                FALSE);\r
9166                 sfree(str);\r
9168                 crStopV;\r
9170             }\r
9172         }\r
9173     }\r
9174     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;\r
9176     /* Clear up various bits and pieces from authentication. */\r
9177     if (s->publickey_blob) {\r
9178         sfree(s->publickey_blob);\r
9179         sfree(s->publickey_comment);\r
9180     }\r
9181     if (s->agent_response)\r
9182         sfree(s->agent_response);\r
9184     if (s->userauth_success) {\r
9185         /*\r
9186          * We've just received USERAUTH_SUCCESS, and we haven't sent any\r
9187          * packets since. Signal the transport layer to consider enacting\r
9188          * delayed compression.\r
9189          *\r
9190          * (Relying on we_are_in is not sufficient, as\r
9191          * draft-miller-secsh-compression-delayed is quite clear that it\r
9192          * triggers on USERAUTH_SUCCESS specifically, and we_are_in can\r
9193          * become set for other reasons.)\r
9194          */\r
9195         do_ssh2_transport(ssh, "enabling delayed compression", -2, NULL);\r
9196     }\r
9198     /*\r
9199      * Now the connection protocol has started, one way or another.\r
9200      */\r
9202     ssh->channels = newtree234(ssh_channelcmp);\r
9204     /*\r
9205      * Set up handlers for some connection protocol messages, so we\r
9206      * don't have to handle them repeatedly in this coroutine.\r
9207      */\r
9208     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] =\r
9209         ssh2_msg_channel_window_adjust;\r
9210     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] =\r
9211         ssh2_msg_global_request;\r
9213     /*\r
9214      * Create the main session channel.\r
9215      */\r
9216     if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) {\r
9217         ssh->mainchan = NULL;\r
9218     } else {\r
9219         ssh->mainchan = snew(struct ssh_channel);\r
9220         ssh->mainchan->ssh = ssh;\r
9221         ssh2_channel_init(ssh->mainchan);\r
9223         if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) {\r
9224             /*\r
9225              * Just start a direct-tcpip channel and use it as the main\r
9226              * channel.\r
9227              */\r
9228             ssh_send_port_open(ssh->mainchan,\r
9229                                conf_get_str(ssh->conf, CONF_ssh_nc_host),\r
9230                                conf_get_int(ssh->conf, CONF_ssh_nc_port),\r
9231                                "main channel");\r
9232             ssh->ncmode = TRUE;\r
9233         } else {\r
9234             s->pktout = ssh2_chanopen_init(ssh->mainchan, "session");\r
9235             logevent("Opening session as main channel");\r
9236             ssh2_pkt_send(ssh, s->pktout);\r
9237             ssh->ncmode = FALSE;\r
9238         }\r
9239         crWaitUntilV(pktin);\r
9240         if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {\r
9241             bombout(("Server refused to open channel"));\r
9242             crStopV;\r
9243             /* FIXME: error data comes back in FAILURE packet */\r
9244         }\r
9245         if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {\r
9246             bombout(("Server's channel confirmation cited wrong channel"));\r
9247             crStopV;\r
9248         }\r
9249         ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);\r
9250         ssh->mainchan->halfopen = FALSE;\r
9251         ssh->mainchan->type = CHAN_MAINSESSION;\r
9252         ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
9253         ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
9254         add234(ssh->channels, ssh->mainchan);\r
9255         update_specials_menu(ssh->frontend);\r
9256         logevent("Opened main channel");\r
9257     }\r
9259     /*\r
9260      * Now we have a channel, make dispatch table entries for\r
9261      * general channel-based messages.\r
9262      */\r
9263     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] =\r
9264     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] =\r
9265         ssh2_msg_channel_data;\r
9266     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof;\r
9267     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close;\r
9268     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
9269         ssh2_msg_channel_open_confirmation;\r
9270     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] =\r
9271         ssh2_msg_channel_open_failure;\r
9272     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] =\r
9273         ssh2_msg_channel_request;\r
9274     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] =\r
9275         ssh2_msg_channel_open;\r
9276     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;\r
9277     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;\r
9280     if (ssh->mainchan && conf_get_int(ssh->conf, CONF_ssh_simple)) {\r
9281         /*\r
9282          * This message indicates to the server that we promise\r
9283          * not to try to run any other channel in parallel with\r
9284          * this one, so it's safe for it to advertise a very large\r
9285          * window and leave the flow control to TCP.\r
9286          */\r
9287         s->pktout = ssh2_chanreq_init(ssh->mainchan,\r
9288                                       "simple@putty.projects.tartarus.org",\r
9289                                       NULL, NULL);\r
9290         ssh2_pkt_send(ssh, s->pktout);\r
9291     }\r
9293     /*\r
9294      * Enable port forwardings.\r
9295      */\r
9296     ssh_setup_portfwd(ssh, ssh->conf);\r
9298     if (ssh->mainchan && !ssh->ncmode) {\r
9299         /*\r
9300          * Send the CHANNEL_REQUESTS for the main session channel.\r
9301          * Each one is handled by its own little asynchronous\r
9302          * co-routine.\r
9303          */\r
9305         /* Potentially enable X11 forwarding. */\r
9306         if (conf_get_int(ssh->conf, CONF_x11_forward) &&\r
9307             (ssh->x11disp =\r
9308              x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),\r
9309                                conf_get_int(ssh->conf, CONF_x11_auth),\r
9310                                ssh->conf)))\r
9311             ssh2_setup_x11(ssh->mainchan, NULL, NULL);\r
9313         /* Potentially enable agent forwarding. */\r
9314         if (conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists())\r
9315             ssh2_setup_agent(ssh->mainchan, NULL, NULL);\r
9317         /* Now allocate a pty for the session. */\r
9318         if (!conf_get_int(ssh->conf, CONF_nopty))\r
9319             ssh2_setup_pty(ssh->mainchan, NULL, NULL);\r
9321         /* Send environment variables. */\r
9322         ssh2_setup_env(ssh->mainchan, NULL, NULL);\r
9324         /*\r
9325          * Start a shell or a remote command. We may have to attempt\r
9326          * this twice if the config data has provided a second choice\r
9327          * of command.\r
9328          */\r
9329         while (1) {\r
9330             int subsys;\r
9331             char *cmd;\r
9333             if (ssh->fallback_cmd) {\r
9334                 subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2);\r
9335                 cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);\r
9336             } else {\r
9337                 subsys = conf_get_int(ssh->conf, CONF_ssh_subsys);\r
9338                 cmd = conf_get_str(ssh->conf, CONF_remote_cmd);\r
9339             }\r
9341             if (subsys) {\r
9342                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem",\r
9343                                               ssh2_response_authconn, NULL);\r
9344                 ssh2_pkt_addstring(s->pktout, cmd);\r
9345             } else if (*cmd) {\r
9346                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec",\r
9347                                               ssh2_response_authconn, NULL);\r
9348                 ssh2_pkt_addstring(s->pktout, cmd);\r
9349             } else {\r
9350                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell",\r
9351                                               ssh2_response_authconn, NULL);\r
9352             }\r
9353             ssh2_pkt_send(ssh, s->pktout);\r
9355             crWaitUntilV(pktin);\r
9357             if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
9358                 if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
9359                     bombout(("Unexpected response to shell/command request:"\r
9360                              " packet type %d", pktin->type));\r
9361                     crStopV;\r
9362                 }\r
9363                 /*\r
9364                  * We failed to start the command. If this is the\r
9365                  * fallback command, we really are finished; if it's\r
9366                  * not, and if the fallback command exists, try falling\r
9367                  * back to it before complaining.\r
9368                  */\r
9369                 if (!ssh->fallback_cmd &&\r
9370                     *conf_get_str(ssh->conf, CONF_remote_cmd2)) {\r
9371                     logevent("Primary command failed; attempting fallback");\r
9372                     ssh->fallback_cmd = TRUE;\r
9373                     continue;\r
9374                 }\r
9375                 bombout(("Server refused to start a shell/command"));\r
9376                 crStopV;\r
9377             } else {\r
9378                 logevent("Started a shell/command");\r
9379             }\r
9380             break;\r
9381         }\r
9382     } else {\r
9383         ssh->editing = ssh->echoing = TRUE;\r
9384     }\r
9386     ssh->state = SSH_STATE_SESSION;\r
9387     if (ssh->size_needed)\r
9388         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
9389     if (ssh->eof_needed)\r
9390         ssh_special(ssh, TS_EOF);\r
9392     /*\r
9393      * Transfer data!\r
9394      */\r
9395     if (ssh->ldisc)\r
9396         ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */\r
9397     if (ssh->mainchan)\r
9398         ssh->send_ok = 1;\r
9399     while (1) {\r
9400         crReturnV;\r
9401         s->try_send = FALSE;\r
9402         if (pktin) {\r
9404             /*\r
9405              * _All_ the connection-layer packets we expect to\r
9406              * receive are now handled by the dispatch table.\r
9407              * Anything that reaches here must be bogus.\r
9408              */\r
9410             bombout(("Strange packet received: type %d", pktin->type));\r
9411             crStopV;\r
9412         } else if (ssh->mainchan) {\r
9413             /*\r
9414              * We have spare data. Add it to the channel buffer.\r
9415              */\r
9416             ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen);\r
9417             s->try_send = TRUE;\r
9418         }\r
9419         if (s->try_send) {\r
9420             int i;\r
9421             struct ssh_channel *c;\r
9422             /*\r
9423              * Try to send data on all channels if we can.\r
9424              */\r
9425             for (i = 0; NULL != (c = index234(ssh->channels, i)); i++)\r
9426                 ssh2_try_send_and_unthrottle(ssh, c);\r
9427         }\r
9428     }\r
9430     crFinishV;\r
9433 /*\r
9434  * Handlers for SSH-2 messages that might arrive at any moment.\r
9435  */\r
9436 static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
9438     /* log reason code in disconnect message */\r
9439     char *buf, *msg;\r
9440     int reason, msglen;\r
9442     reason = ssh_pkt_getuint32(pktin);\r
9443     ssh_pkt_getstring(pktin, &msg, &msglen);\r
9445     if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {\r
9446         buf = dupprintf("Received disconnect message (%s)",\r
9447                         ssh2_disconnect_reasons[reason]);\r
9448     } else {\r
9449         buf = dupprintf("Received disconnect message (unknown"\r
9450                         " type %d)", reason);\r
9451     }\r
9452     logevent(buf);\r
9453     sfree(buf);\r
9454     buf = dupprintf("Disconnection message text: %.*s",\r
9455                     msglen, msg);\r
9456     logevent(buf);\r
9457     bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"",\r
9458              reason,\r
9459              (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?\r
9460              ssh2_disconnect_reasons[reason] : "unknown",\r
9461              msglen, msg));\r
9462     sfree(buf);\r
9465 static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)\r
9467     /* log the debug message */\r
9468     char *msg;\r
9469     int msglen;\r
9471     /* XXX maybe we should actually take notice of the return value */\r
9472     ssh2_pkt_getbool(pktin);\r
9473     ssh_pkt_getstring(pktin, &msg, &msglen);\r
9475     logeventf(ssh, "Remote debug message: %.*s", msglen, msg);\r
9478 static void ssh2_msg_transport(Ssh ssh, struct Packet *pktin)\r
9480     do_ssh2_transport(ssh, NULL, 0, pktin);\r
9483 /*\r
9484  * Called if we receive a packet that isn't allowed by the protocol.\r
9485  * This only applies to packets whose meaning PuTTY understands.\r
9486  * Entirely unknown packets are handled below.\r
9487  */\r
9488 static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin)\r
9490     char *buf = dupprintf("Server protocol violation: unexpected %s packet",\r
9491                           ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
9492                                         pktin->type));\r
9493     ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
9494     sfree(buf);\r
9497 static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)\r
9499     struct Packet *pktout;\r
9500     pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);\r
9501     ssh2_pkt_adduint32(pktout, pktin->sequence);\r
9502     /*\r
9503      * UNIMPLEMENTED messages MUST appear in the same order as the\r
9504      * messages they respond to. Hence, never queue them.\r
9505      */\r
9506     ssh2_pkt_send_noqueue(ssh, pktout);\r
9509 /*\r
9510  * Handle the top-level SSH-2 protocol.\r
9511  */\r
9512 static void ssh2_protocol_setup(Ssh ssh)\r
9514     int i;\r
9516     /*\r
9517      * Most messages cause SSH2_MSG_UNIMPLEMENTED.\r
9518      */\r
9519     for (i = 0; i < 256; i++)\r
9520         ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;\r
9522     /*\r
9523      * Initially, we only accept transport messages (and a few generic\r
9524      * ones).  do_ssh2_authconn will add more when it starts.\r
9525      * Messages that are understood but not currently acceptable go to\r
9526      * ssh2_msg_unexpected.\r
9527      */\r
9528     ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected;\r
9529     ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = ssh2_msg_unexpected;\r
9530     ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_unexpected;\r
9531     ssh->packet_dispatch[SSH2_MSG_KEXINIT] = ssh2_msg_transport;\r
9532     ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = ssh2_msg_transport;\r
9533     ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = ssh2_msg_transport;\r
9534     ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = ssh2_msg_transport;\r
9535     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = ssh2_msg_transport; duplicate case value */\r
9536     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = ssh2_msg_transport; duplicate case value */\r
9537     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = ssh2_msg_transport;\r
9538     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = ssh2_msg_transport;\r
9539     ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_unexpected;\r
9540     ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_unexpected;\r
9541     ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_unexpected;\r
9542     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_unexpected;\r
9543     ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_unexpected;\r
9544     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_unexpected; duplicate case value */\r
9545     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_unexpected; duplicate case value */\r
9546     ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_unexpected;\r
9547     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected;\r
9548     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected;\r
9549     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected;\r
9550     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected;\r
9551     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected;\r
9552     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected;\r
9553     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected;\r
9554     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected;\r
9555     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected;\r
9556     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected;\r
9557     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected;\r
9558     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected;\r
9559     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected;\r
9560     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected;\r
9562     /*\r
9563      * These messages have a special handler from the start.\r
9564      */\r
9565     ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;\r
9566     ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with SSH-1 */\r
9567     ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;\r
9570 static void ssh2_timer(void *ctx, unsigned long now)\r
9572     Ssh ssh = (Ssh)ctx;\r
9574     if (ssh->state == SSH_STATE_CLOSED)\r
9575         return;\r
9577     if (!ssh->kex_in_progress && conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0 &&\r
9578         now == ssh->next_rekey) {\r
9579         do_ssh2_transport(ssh, "timeout", -1, NULL);\r
9580     }\r
9583 static void ssh2_protocol(Ssh ssh, void *vin, int inlen,\r
9584                           struct Packet *pktin)\r
9586     unsigned char *in = (unsigned char *)vin;\r
9587     if (ssh->state == SSH_STATE_CLOSED)\r
9588         return;\r
9590     if (pktin) {\r
9591         ssh->incoming_data_size += pktin->encrypted_len;\r
9592         if (!ssh->kex_in_progress &&\r
9593             ssh->max_data_size != 0 &&\r
9594             ssh->incoming_data_size > ssh->max_data_size)\r
9595             do_ssh2_transport(ssh, "too much data received", -1, NULL);\r
9596     }\r
9598     if (pktin)\r
9599         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
9600     else if (!ssh->protocol_initial_phase_done)\r
9601         do_ssh2_transport(ssh, in, inlen, pktin);\r
9602     else\r
9603         do_ssh2_authconn(ssh, in, inlen, pktin);\r
9606 static void ssh_cache_conf_values(Ssh ssh)\r
9608     ssh->logomitdata = conf_get_int(ssh->conf, CONF_logomitdata);\r
9611 /*\r
9612  * Called to set up the connection.\r
9613  *\r
9614  * Returns an error message, or NULL on success.\r
9615  */\r
9616 static const char *ssh_init(void *frontend_handle, void **backend_handle,\r
9617                             Conf *conf, char *host, int port, char **realhost,\r
9618                             int nodelay, int keepalive)\r
9620     const char *p;\r
9621     Ssh ssh;\r
9623     ssh = snew(struct ssh_tag);\r
9624     ssh->conf = conf_copy(conf);\r
9625     ssh_cache_conf_values(ssh);\r
9626     ssh->version = 0;                  /* when not ready yet */\r
9627     ssh->s = NULL;\r
9628     ssh->cipher = NULL;\r
9629     ssh->v1_cipher_ctx = NULL;\r
9630     ssh->crcda_ctx = NULL;\r
9631     ssh->cscipher = NULL;\r
9632     ssh->cs_cipher_ctx = NULL;\r
9633     ssh->sccipher = NULL;\r
9634     ssh->sc_cipher_ctx = NULL;\r
9635     ssh->csmac = NULL;\r
9636     ssh->cs_mac_ctx = NULL;\r
9637     ssh->scmac = NULL;\r
9638     ssh->sc_mac_ctx = NULL;\r
9639     ssh->cscomp = NULL;\r
9640     ssh->cs_comp_ctx = NULL;\r
9641     ssh->sccomp = NULL;\r
9642     ssh->sc_comp_ctx = NULL;\r
9643     ssh->kex = NULL;\r
9644     ssh->kex_ctx = NULL;\r
9645     ssh->hostkey = NULL;\r
9646     ssh->exitcode = -1;\r
9647     ssh->close_expected = FALSE;\r
9648     ssh->clean_exit = FALSE;\r
9649     ssh->state = SSH_STATE_PREPACKET;\r
9650     ssh->size_needed = FALSE;\r
9651     ssh->eof_needed = FALSE;\r
9652     ssh->ldisc = NULL;\r
9653     ssh->logctx = NULL;\r
9654     ssh->deferred_send_data = NULL;\r
9655     ssh->deferred_len = 0;\r
9656     ssh->deferred_size = 0;\r
9657     ssh->fallback_cmd = 0;\r
9658     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
9659     ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
9660     ssh->x11disp = NULL;\r
9661     ssh->v1_compressing = FALSE;\r
9662     ssh->v2_outgoing_sequence = 0;\r
9663     ssh->ssh1_rdpkt_crstate = 0;\r
9664     ssh->ssh2_rdpkt_crstate = 0;\r
9665     ssh->ssh_gotdata_crstate = 0;\r
9666     ssh->do_ssh1_connection_crstate = 0;\r
9667     ssh->do_ssh_init_state = NULL;\r
9668     ssh->do_ssh1_login_state = NULL;\r
9669     ssh->do_ssh2_transport_state = NULL;\r
9670     ssh->do_ssh2_authconn_state = NULL;\r
9671     ssh->v_c = NULL;\r
9672     ssh->v_s = NULL;\r
9673     ssh->mainchan = NULL;\r
9674     ssh->throttled_all = 0;\r
9675     ssh->v1_stdout_throttling = 0;\r
9676     ssh->queue = NULL;\r
9677     ssh->queuelen = ssh->queuesize = 0;\r
9678     ssh->queueing = FALSE;\r
9679     ssh->qhead = ssh->qtail = NULL;\r
9680     ssh->deferred_rekey_reason = NULL;\r
9681     bufchain_init(&ssh->queued_incoming_data);\r
9682     ssh->frozen = FALSE;\r
9683     ssh->username = NULL;\r
9684     ssh->sent_console_eof = FALSE;\r
9685     ssh->got_pty = FALSE;\r
9687     *backend_handle = ssh;\r
9689 #ifdef MSCRYPTOAPI\r
9690     if (crypto_startup() == 0)\r
9691         return "Microsoft high encryption pack not installed!";\r
9692 #endif\r
9694     ssh->frontend = frontend_handle;\r
9695     ssh->term_width = conf_get_int(ssh->conf, CONF_width);\r
9696     ssh->term_height = conf_get_int(ssh->conf, CONF_height);\r
9698     ssh->channels = NULL;\r
9699     ssh->rportfwds = NULL;\r
9700     ssh->portfwds = NULL;\r
9702     ssh->send_ok = 0;\r
9703     ssh->editing = 0;\r
9704     ssh->echoing = 0;\r
9705     ssh->conn_throttle_count = 0;\r
9706     ssh->overall_bufsize = 0;\r
9707     ssh->fallback_cmd = 0;\r
9709     ssh->protocol = NULL;\r
9711     ssh->protocol_initial_phase_done = FALSE;\r
9713     ssh->pinger = NULL;\r
9715     ssh->incoming_data_size = ssh->outgoing_data_size =\r
9716         ssh->deferred_data_size = 0L;\r
9717     ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf,\r
9718                                                       CONF_ssh_rekey_data));\r
9719     ssh->kex_in_progress = FALSE;\r
9721 #ifndef NO_GSSAPI\r
9722     ssh->gsslibs = NULL;\r
9723 #endif\r
9725     p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);\r
9726     if (p != NULL)\r
9727         return p;\r
9729     random_ref();\r
9731     return NULL;\r
9734 static void ssh_free(void *handle)\r
9736     Ssh ssh = (Ssh) handle;\r
9737     struct ssh_channel *c;\r
9738     struct ssh_rportfwd *pf;\r
9740     if (ssh->v1_cipher_ctx)\r
9741         ssh->cipher->free_context(ssh->v1_cipher_ctx);\r
9742     if (ssh->cs_cipher_ctx)\r
9743         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
9744     if (ssh->sc_cipher_ctx)\r
9745         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
9746     if (ssh->cs_mac_ctx)\r
9747         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
9748     if (ssh->sc_mac_ctx)\r
9749         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
9750     if (ssh->cs_comp_ctx) {\r
9751         if (ssh->cscomp)\r
9752             ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
9753         else\r
9754             zlib_compress_cleanup(ssh->cs_comp_ctx);\r
9755     }\r
9756     if (ssh->sc_comp_ctx) {\r
9757         if (ssh->sccomp)\r
9758             ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
9759         else\r
9760             zlib_decompress_cleanup(ssh->sc_comp_ctx);\r
9761     }\r
9762     if (ssh->kex_ctx)\r
9763         dh_cleanup(ssh->kex_ctx);\r
9764     sfree(ssh->savedhost);\r
9766     while (ssh->queuelen-- > 0)\r
9767         ssh_free_packet(ssh->queue[ssh->queuelen]);\r
9768     sfree(ssh->queue);\r
9770     while (ssh->qhead) {\r
9771         struct queued_handler *qh = ssh->qhead;\r
9772         ssh->qhead = qh->next;\r
9773         sfree(qh);\r
9774     }\r
9775     ssh->qhead = ssh->qtail = NULL;\r
9777     if (ssh->channels) {\r
9778         while ((c = delpos234(ssh->channels, 0)) != NULL) {\r
9779             switch (c->type) {\r
9780               case CHAN_X11:\r
9781                 if (c->u.x11.s != NULL)\r
9782                     x11_close(c->u.x11.s);\r
9783                 break;\r
9784               case CHAN_SOCKDATA:\r
9785               case CHAN_SOCKDATA_DORMANT:\r
9786                 if (c->u.pfd.s != NULL)\r
9787                     pfd_close(c->u.pfd.s);\r
9788                 break;\r
9789             }\r
9790             if (ssh->version == 2) {\r
9791                 struct outstanding_channel_request *ocr, *nocr;\r
9792                 ocr = c->v.v2.chanreq_head;\r
9793                 while (ocr) {\r
9794                     ocr->handler(c, NULL, ocr->ctx);\r
9795                     nocr = ocr->next;\r
9796                     sfree(ocr);\r
9797                     ocr = nocr;\r
9798                 }\r
9799                 bufchain_clear(&c->v.v2.outbuffer);\r
9800             }\r
9801             sfree(c);\r
9802         }\r
9803         freetree234(ssh->channels);\r
9804         ssh->channels = NULL;\r
9805     }\r
9807     if (ssh->rportfwds) {\r
9808         while ((pf = delpos234(ssh->rportfwds, 0)) != NULL)\r
9809             free_rportfwd(pf);\r
9810         freetree234(ssh->rportfwds);\r
9811         ssh->rportfwds = NULL;\r
9812     }\r
9813     sfree(ssh->deferred_send_data);\r
9814     if (ssh->x11disp)\r
9815         x11_free_display(ssh->x11disp);\r
9816     sfree(ssh->do_ssh_init_state);\r
9817     sfree(ssh->do_ssh1_login_state);\r
9818     sfree(ssh->do_ssh2_transport_state);\r
9819     sfree(ssh->do_ssh2_authconn_state);\r
9820     sfree(ssh->v_c);\r
9821     sfree(ssh->v_s);\r
9822     sfree(ssh->fullhostname);\r
9823     if (ssh->crcda_ctx) {\r
9824         crcda_free_context(ssh->crcda_ctx);\r
9825         ssh->crcda_ctx = NULL;\r
9826     }\r
9827     if (ssh->s)\r
9828         ssh_do_close(ssh, TRUE);\r
9829     expire_timer_context(ssh);\r
9830     if (ssh->pinger)\r
9831         pinger_free(ssh->pinger);\r
9832     bufchain_clear(&ssh->queued_incoming_data);\r
9833     sfree(ssh->username);\r
9834     conf_free(ssh->conf);\r
9835 #ifndef NO_GSSAPI\r
9836     if (ssh->gsslibs)\r
9837         ssh_gss_cleanup(ssh->gsslibs);\r
9838 #endif\r
9839     sfree(ssh);\r
9841     random_unref();\r
9844 /*\r
9845  * Reconfigure the SSH backend.\r
9846  */\r
9847 static void ssh_reconfig(void *handle, Conf *conf)\r
9849     Ssh ssh = (Ssh) handle;\r
9850     char *rekeying = NULL, rekey_mandatory = FALSE;\r
9851     unsigned long old_max_data_size;\r
9852     int i, rekey_time;\r
9854     pinger_reconfig(ssh->pinger, ssh->conf, conf);\r
9855     if (ssh->portfwds)\r
9856         ssh_setup_portfwd(ssh, conf);\r
9858     rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);\r
9859     if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != rekey_time &&\r
9860         rekey_time != 0) {\r
9861         unsigned long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;\r
9862         unsigned long now = GETTICKCOUNT();\r
9864         if (now - ssh->last_rekey > rekey_time*60*TICKSPERSEC) {\r
9865             rekeying = "timeout shortened";\r
9866         } else {\r
9867             ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh);\r
9868         }\r
9869     }\r
9871     old_max_data_size = ssh->max_data_size;\r
9872     ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf,\r
9873                                                       CONF_ssh_rekey_data));\r
9874     if (old_max_data_size != ssh->max_data_size &&\r
9875         ssh->max_data_size != 0) {\r
9876         if (ssh->outgoing_data_size > ssh->max_data_size ||\r
9877             ssh->incoming_data_size > ssh->max_data_size)\r
9878             rekeying = "data limit lowered";\r
9879     }\r
9881     if (conf_get_int(ssh->conf, CONF_compression) !=\r
9882         conf_get_int(conf, CONF_compression)) {\r
9883         rekeying = "compression setting changed";\r
9884         rekey_mandatory = TRUE;\r
9885     }\r
9887     for (i = 0; i < CIPHER_MAX; i++)\r
9888         if (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i) !=\r
9889             conf_get_int_int(conf, CONF_ssh_cipherlist, i)) {\r
9890         rekeying = "cipher settings changed";\r
9891         rekey_mandatory = TRUE;\r
9892     }\r
9893     if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc) !=\r
9894         conf_get_int(conf, CONF_ssh2_des_cbc)) {\r
9895         rekeying = "cipher settings changed";\r
9896         rekey_mandatory = TRUE;\r
9897     }\r
9899     conf_free(ssh->conf);\r
9900     ssh->conf = conf_copy(conf);\r
9901     ssh_cache_conf_values(ssh);\r
9903     if (rekeying) {\r
9904         if (!ssh->kex_in_progress) {\r
9905             do_ssh2_transport(ssh, rekeying, -1, NULL);\r
9906         } else if (rekey_mandatory) {\r
9907             ssh->deferred_rekey_reason = rekeying;\r
9908         }\r
9909     }\r
9912 /*\r
9913  * Called to send data down the SSH connection.\r
9914  */\r
9915 static int ssh_send(void *handle, char *buf, int len)\r
9917     Ssh ssh = (Ssh) handle;\r
9919     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
9920         return 0;\r
9922     ssh->protocol(ssh, (unsigned char *)buf, len, 0);\r
9924     return ssh_sendbuffer(ssh);\r
9927 /*\r
9928  * Called to query the current amount of buffered stdin data.\r
9929  */\r
9930 static int ssh_sendbuffer(void *handle)\r
9932     Ssh ssh = (Ssh) handle;\r
9933     int override_value;\r
9935     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
9936         return 0;\r
9938     /*\r
9939      * If the SSH socket itself has backed up, add the total backup\r
9940      * size on that to any individual buffer on the stdin channel.\r
9941      */\r
9942     override_value = 0;\r
9943     if (ssh->throttled_all)\r
9944         override_value = ssh->overall_bufsize;\r
9946     if (ssh->version == 1) {\r
9947         return override_value;\r
9948     } else if (ssh->version == 2) {\r
9949         if (!ssh->mainchan)\r
9950             return override_value;\r
9951         else\r
9952             return (override_value +\r
9953                     bufchain_size(&ssh->mainchan->v.v2.outbuffer));\r
9954     }\r
9956     return 0;\r
9959 /*\r
9960  * Called to set the size of the window from SSH's POV.\r
9961  */\r
9962 static void ssh_size(void *handle, int width, int height)\r
9964     Ssh ssh = (Ssh) handle;\r
9965     struct Packet *pktout;\r
9967     ssh->term_width = width;\r
9968     ssh->term_height = height;\r
9970     switch (ssh->state) {\r
9971       case SSH_STATE_BEFORE_SIZE:\r
9972       case SSH_STATE_PREPACKET:\r
9973       case SSH_STATE_CLOSED:\r
9974         break;                         /* do nothing */\r
9975       case SSH_STATE_INTERMED:\r
9976         ssh->size_needed = TRUE;       /* buffer for later */\r
9977         break;\r
9978       case SSH_STATE_SESSION:\r
9979         if (!conf_get_int(ssh->conf, CONF_nopty)) {\r
9980             if (ssh->version == 1) {\r
9981                 send_packet(ssh, SSH1_CMSG_WINDOW_SIZE,\r
9982                             PKT_INT, ssh->term_height,\r
9983                             PKT_INT, ssh->term_width,\r
9984                             PKT_INT, 0, PKT_INT, 0, PKT_END);\r
9985             } else if (ssh->mainchan) {\r
9986                 pktout = ssh2_chanreq_init(ssh->mainchan, "window-change",\r
9987                                            NULL, NULL);\r
9988                 ssh2_pkt_adduint32(pktout, ssh->term_width);\r
9989                 ssh2_pkt_adduint32(pktout, ssh->term_height);\r
9990                 ssh2_pkt_adduint32(pktout, 0);\r
9991                 ssh2_pkt_adduint32(pktout, 0);\r
9992                 ssh2_pkt_send(ssh, pktout);\r
9993             }\r
9994         }\r
9995         break;\r
9996     }\r
9999 /*\r
10000  * Return a list of the special codes that make sense in this\r
10001  * protocol.\r
10002  */\r
10003 static const struct telnet_special *ssh_get_specials(void *handle)\r
10005     static const struct telnet_special ssh1_ignore_special[] = {\r
10006         {"IGNORE message", TS_NOP}\r
10007     };\r
10008     static const struct telnet_special ssh2_ignore_special[] = {\r
10009         {"IGNORE message", TS_NOP},\r
10010     };\r
10011     static const struct telnet_special ssh2_rekey_special[] = {\r
10012         {"Repeat key exchange", TS_REKEY},\r
10013     };\r
10014     static const struct telnet_special ssh2_session_specials[] = {\r
10015         {NULL, TS_SEP},\r
10016         {"Break", TS_BRK},\r
10017         /* These are the signal names defined by RFC 4254.\r
10018          * They include all the ISO C signals, but are a subset of the POSIX\r
10019          * required signals. */\r
10020         {"SIGINT (Interrupt)", TS_SIGINT},\r
10021         {"SIGTERM (Terminate)", TS_SIGTERM},\r
10022         {"SIGKILL (Kill)", TS_SIGKILL},\r
10023         {"SIGQUIT (Quit)", TS_SIGQUIT},\r
10024         {"SIGHUP (Hangup)", TS_SIGHUP},\r
10025         {"More signals", TS_SUBMENU},\r
10026           {"SIGABRT", TS_SIGABRT}, {"SIGALRM", TS_SIGALRM},\r
10027           {"SIGFPE",  TS_SIGFPE},  {"SIGILL",  TS_SIGILL},\r
10028           {"SIGPIPE", TS_SIGPIPE}, {"SIGSEGV", TS_SIGSEGV},\r
10029           {"SIGUSR1", TS_SIGUSR1}, {"SIGUSR2", TS_SIGUSR2},\r
10030         {NULL, TS_EXITMENU}\r
10031     };\r
10032     static const struct telnet_special specials_end[] = {\r
10033         {NULL, TS_EXITMENU}\r
10034     };\r
10035     /* XXX review this length for any changes: */\r
10036     static struct telnet_special ssh_specials[lenof(ssh2_ignore_special) +\r
10037                                               lenof(ssh2_rekey_special) +\r
10038                                               lenof(ssh2_session_specials) +\r
10039                                               lenof(specials_end)];\r
10040     Ssh ssh = (Ssh) handle;\r
10041     int i = 0;\r
10042 #define ADD_SPECIALS(name) \\r
10043     do { \\r
10044         assert((i + lenof(name)) <= lenof(ssh_specials)); \\r
10045         memcpy(&ssh_specials[i], name, sizeof name); \\r
10046         i += lenof(name); \\r
10047     } while(0)\r
10049     if (ssh->version == 1) {\r
10050         /* Don't bother offering IGNORE if we've decided the remote\r
10051          * won't cope with it, since we wouldn't bother sending it if\r
10052          * asked anyway. */\r
10053         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
10054             ADD_SPECIALS(ssh1_ignore_special);\r
10055     } else if (ssh->version == 2) {\r
10056         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE))\r
10057             ADD_SPECIALS(ssh2_ignore_special);\r
10058         if (!(ssh->remote_bugs & BUG_SSH2_REKEY))\r
10059             ADD_SPECIALS(ssh2_rekey_special);\r
10060         if (ssh->mainchan)\r
10061             ADD_SPECIALS(ssh2_session_specials);\r
10062     } /* else we're not ready yet */\r
10064     if (i) {\r
10065         ADD_SPECIALS(specials_end);\r
10066         return ssh_specials;\r
10067     } else {\r
10068         return NULL;\r
10069     }\r
10070 #undef ADD_SPECIALS\r
10073 /*\r
10074  * Send special codes. TS_EOF is useful for `plink', so you\r
10075  * can send an EOF and collect resulting output (e.g. `plink\r
10076  * hostname sort').\r
10077  */\r
10078 static void ssh_special(void *handle, Telnet_Special code)\r
10080     Ssh ssh = (Ssh) handle;\r
10081     struct Packet *pktout;\r
10083     if (code == TS_EOF) {\r
10084         if (ssh->state != SSH_STATE_SESSION) {\r
10085             /*\r
10086              * Buffer the EOF in case we are pre-SESSION, so we can\r
10087              * send it as soon as we reach SESSION.\r
10088              */\r
10089             if (code == TS_EOF)\r
10090                 ssh->eof_needed = TRUE;\r
10091             return;\r
10092         }\r
10093         if (ssh->version == 1) {\r
10094             send_packet(ssh, SSH1_CMSG_EOF, PKT_END);\r
10095         } else if (ssh->mainchan) {\r
10096             sshfwd_write_eof(ssh->mainchan);\r
10097             ssh->send_ok = 0;          /* now stop trying to read from stdin */\r
10098         }\r
10099         logevent("Sent EOF message");\r
10100     } else if (code == TS_PING || code == TS_NOP) {\r
10101         if (ssh->state == SSH_STATE_CLOSED\r
10102             || ssh->state == SSH_STATE_PREPACKET) return;\r
10103         if (ssh->version == 1) {\r
10104             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
10105                 send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);\r
10106         } else {\r
10107             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
10108                 pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
10109                 ssh2_pkt_addstring_start(pktout);\r
10110                 ssh2_pkt_send_noqueue(ssh, pktout);\r
10111             }\r
10112         }\r
10113     } else if (code == TS_REKEY) {\r
10114         if (!ssh->kex_in_progress && ssh->version == 2) {\r
10115             do_ssh2_transport(ssh, "at user request", -1, NULL);\r
10116         }\r
10117     } else if (code == TS_BRK) {\r
10118         if (ssh->state == SSH_STATE_CLOSED\r
10119             || ssh->state == SSH_STATE_PREPACKET) return;\r
10120         if (ssh->version == 1) {\r
10121             logevent("Unable to send BREAK signal in SSH-1");\r
10122         } else if (ssh->mainchan) {\r
10123             pktout = ssh2_chanreq_init(ssh->mainchan, "break", NULL, NULL);\r
10124             ssh2_pkt_adduint32(pktout, 0);   /* default break length */\r
10125             ssh2_pkt_send(ssh, pktout);\r
10126         }\r
10127     } else {\r
10128         /* Is is a POSIX signal? */\r
10129         char *signame = NULL;\r
10130         if (code == TS_SIGABRT) signame = "ABRT";\r
10131         if (code == TS_SIGALRM) signame = "ALRM";\r
10132         if (code == TS_SIGFPE)  signame = "FPE";\r
10133         if (code == TS_SIGHUP)  signame = "HUP";\r
10134         if (code == TS_SIGILL)  signame = "ILL";\r
10135         if (code == TS_SIGINT)  signame = "INT";\r
10136         if (code == TS_SIGKILL) signame = "KILL";\r
10137         if (code == TS_SIGPIPE) signame = "PIPE";\r
10138         if (code == TS_SIGQUIT) signame = "QUIT";\r
10139         if (code == TS_SIGSEGV) signame = "SEGV";\r
10140         if (code == TS_SIGTERM) signame = "TERM";\r
10141         if (code == TS_SIGUSR1) signame = "USR1";\r
10142         if (code == TS_SIGUSR2) signame = "USR2";\r
10143         /* The SSH-2 protocol does in principle support arbitrary named\r
10144          * signals, including signame@domain, but we don't support those. */\r
10145         if (signame) {\r
10146             /* It's a signal. */\r
10147             if (ssh->version == 2 && ssh->mainchan) {\r
10148                 pktout = ssh2_chanreq_init(ssh->mainchan, "signal", NULL, NULL);\r
10149                 ssh2_pkt_addstring(pktout, signame);\r
10150                 ssh2_pkt_send(ssh, pktout);\r
10151                 logeventf(ssh, "Sent signal SIG%s", signame);\r
10152             }\r
10153         } else {\r
10154             /* Never heard of it. Do nothing */\r
10155         }\r
10156     }\r
10159 void *new_sock_channel(void *handle, Socket s)\r
10161     Ssh ssh = (Ssh) handle;\r
10162     struct ssh_channel *c;\r
10163     c = snew(struct ssh_channel);\r
10165     c->ssh = ssh;\r
10166     ssh2_channel_init(c);\r
10167     c->halfopen = TRUE;\r
10168     c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */\r
10169     c->u.pfd.s = s;\r
10170     add234(ssh->channels, c);\r
10171     return c;\r
10174 /*\r
10175  * This is called when stdout/stderr (the entity to which\r
10176  * from_backend sends data) manages to clear some backlog.\r
10177  */\r
10178 static void ssh_unthrottle(void *handle, int bufsize)\r
10180     Ssh ssh = (Ssh) handle;\r
10181     int buflimit;\r
10183     if (ssh->version == 1) {\r
10184         if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {\r
10185             ssh->v1_stdout_throttling = 0;\r
10186             ssh_throttle_conn(ssh, -1);\r
10187         }\r
10188     } else {\r
10189         if (ssh->mainchan) {\r
10190             ssh2_set_window(ssh->mainchan,\r
10191                             bufsize < ssh->mainchan->v.v2.locmaxwin ?\r
10192                             ssh->mainchan->v.v2.locmaxwin - bufsize : 0);\r
10193             if (conf_get_int(ssh->conf, CONF_ssh_simple))\r
10194                 buflimit = 0;\r
10195             else\r
10196                 buflimit = ssh->mainchan->v.v2.locmaxwin;\r
10197             if (ssh->mainchan->throttling_conn && bufsize <= buflimit) {\r
10198                 ssh->mainchan->throttling_conn = 0;\r
10199                 ssh_throttle_conn(ssh, -1);\r
10200             }\r
10201         }\r
10202     }\r
10204     /*\r
10205      * Now process any SSH connection data that was stashed in our\r
10206      * queue while we were frozen.\r
10207      */\r
10208     ssh_process_queued_incoming_data(ssh);\r
10211 void ssh_send_port_open(void *channel, char *hostname, int port, char *org)\r
10213     struct ssh_channel *c = (struct ssh_channel *)channel;\r
10214     Ssh ssh = c->ssh;\r
10215     struct Packet *pktout;\r
10217     logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org);\r
10219     if (ssh->version == 1) {\r
10220         send_packet(ssh, SSH1_MSG_PORT_OPEN,\r
10221                     PKT_INT, c->localid,\r
10222                     PKT_STR, hostname,\r
10223                     PKT_INT, port,\r
10224                     /* PKT_STR, <org:orgport>, */\r
10225                     PKT_END);\r
10226     } else {\r
10227         pktout = ssh2_chanopen_init(c, "direct-tcpip");\r
10228         ssh2_pkt_addstring(pktout, hostname);\r
10229         ssh2_pkt_adduint32(pktout, port);\r
10230         /*\r
10231          * We make up values for the originator data; partly it's\r
10232          * too much hassle to keep track, and partly I'm not\r
10233          * convinced the server should be told details like that\r
10234          * about my local network configuration.\r
10235          * The "originator IP address" is syntactically a numeric\r
10236          * IP address, and some servers (e.g., Tectia) get upset\r
10237          * if it doesn't match this syntax.\r
10238          */\r
10239         ssh2_pkt_addstring(pktout, "0.0.0.0");\r
10240         ssh2_pkt_adduint32(pktout, 0);\r
10241         ssh2_pkt_send(ssh, pktout);\r
10242     }\r
10245 static int ssh_connected(void *handle)\r
10247     Ssh ssh = (Ssh) handle;\r
10248     return ssh->s != NULL;\r
10251 static int ssh_sendok(void *handle)\r
10253     Ssh ssh = (Ssh) handle;\r
10254     return ssh->send_ok;\r
10257 static int ssh_ldisc(void *handle, int option)\r
10259     Ssh ssh = (Ssh) handle;\r
10260     if (option == LD_ECHO)\r
10261         return ssh->echoing;\r
10262     if (option == LD_EDIT)\r
10263         return ssh->editing;\r
10264     return FALSE;\r
10267 static void ssh_provide_ldisc(void *handle, void *ldisc)\r
10269     Ssh ssh = (Ssh) handle;\r
10270     ssh->ldisc = ldisc;\r
10273 static void ssh_provide_logctx(void *handle, void *logctx)\r
10275     Ssh ssh = (Ssh) handle;\r
10276     ssh->logctx = logctx;\r
10279 static int ssh_return_exitcode(void *handle)\r
10281     Ssh ssh = (Ssh) handle;\r
10282     if (ssh->s != NULL)\r
10283         return -1;\r
10284     else\r
10285         return (ssh->exitcode >= 0 ? ssh->exitcode : INT_MAX);\r
10288 /*\r
10289  * cfg_info for SSH is the currently running version of the\r
10290  * protocol. (1 for 1; 2 for 2; 0 for not-decided-yet.)\r
10291  */\r
10292 static int ssh_cfg_info(void *handle)\r
10294     Ssh ssh = (Ssh) handle;\r
10295     return ssh->version;\r
10298 /*\r
10299  * Gross hack: pscp will try to start SFTP but fall back to scp1 if\r
10300  * that fails. This variable is the means by which scp.c can reach\r
10301  * into the SSH code and find out which one it got.\r
10302  */\r
10303 extern int ssh_fallback_cmd(void *handle)\r
10305     Ssh ssh = (Ssh) handle;\r
10306     return ssh->fallback_cmd;\r
10309 Backend ssh_backend = {\r
10310     ssh_init,\r
10311     ssh_free,\r
10312     ssh_reconfig,\r
10313     ssh_send,\r
10314     ssh_sendbuffer,\r
10315     ssh_size,\r
10316     ssh_special,\r
10317     ssh_get_specials,\r
10318     ssh_connected,\r
10319     ssh_return_exitcode,\r
10320     ssh_sendok,\r
10321     ssh_ldisc,\r
10322     ssh_provide_ldisc,\r
10323     ssh_provide_logctx,\r
10324     ssh_unthrottle,\r
10325     ssh_cfg_info,\r
10326     "ssh",\r
10327     PROT_SSH,\r
10328     22\r
10329 };\r