drop unreferenced code
[TortoiseGit.git] / src / TortoisePlink / SSH.C
blob6b7eb8d9de7c06120b750ad48f75ba0770ab9cf1
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
200 /*\r
201  * Codes for terminal modes.\r
202  * Most of these are the same in SSH-1 and SSH-2.\r
203  * This list is derived from RFC 4254 and\r
204  * SSH-1 RFC-1.2.31.\r
205  */\r
206 static const struct {\r
207     const char* const mode;\r
208     int opcode;\r
209     enum { TTY_OP_CHAR, TTY_OP_BOOL } type;\r
210 } ssh_ttymodes[] = {\r
211     /* "V" prefix discarded for special characters relative to SSH specs */\r
212     { "INTR",         1, TTY_OP_CHAR },\r
213     { "QUIT",         2, TTY_OP_CHAR },\r
214     { "ERASE",        3, TTY_OP_CHAR },\r
215     { "KILL",         4, TTY_OP_CHAR },\r
216     { "EOF",          5, TTY_OP_CHAR },\r
217     { "EOL",          6, TTY_OP_CHAR },\r
218     { "EOL2",         7, TTY_OP_CHAR },\r
219     { "START",        8, TTY_OP_CHAR },\r
220     { "STOP",         9, TTY_OP_CHAR },\r
221     { "SUSP",        10, TTY_OP_CHAR },\r
222     { "DSUSP",       11, TTY_OP_CHAR },\r
223     { "REPRINT",     12, TTY_OP_CHAR },\r
224     { "WERASE",      13, TTY_OP_CHAR },\r
225     { "LNEXT",       14, TTY_OP_CHAR },\r
226     { "FLUSH",       15, TTY_OP_CHAR },\r
227     { "SWTCH",       16, TTY_OP_CHAR },\r
228     { "STATUS",      17, TTY_OP_CHAR },\r
229     { "DISCARD",     18, TTY_OP_CHAR },\r
230     { "IGNPAR",      30, TTY_OP_BOOL },\r
231     { "PARMRK",      31, TTY_OP_BOOL },\r
232     { "INPCK",       32, TTY_OP_BOOL },\r
233     { "ISTRIP",      33, TTY_OP_BOOL },\r
234     { "INLCR",       34, TTY_OP_BOOL },\r
235     { "IGNCR",       35, TTY_OP_BOOL },\r
236     { "ICRNL",       36, TTY_OP_BOOL },\r
237     { "IUCLC",       37, TTY_OP_BOOL },\r
238     { "IXON",        38, TTY_OP_BOOL },\r
239     { "IXANY",       39, TTY_OP_BOOL },\r
240     { "IXOFF",       40, TTY_OP_BOOL },\r
241     { "IMAXBEL",     41, TTY_OP_BOOL },\r
242     { "ISIG",        50, TTY_OP_BOOL },\r
243     { "ICANON",      51, TTY_OP_BOOL },\r
244     { "XCASE",       52, TTY_OP_BOOL },\r
245     { "ECHO",        53, TTY_OP_BOOL },\r
246     { "ECHOE",       54, TTY_OP_BOOL },\r
247     { "ECHOK",       55, TTY_OP_BOOL },\r
248     { "ECHONL",      56, TTY_OP_BOOL },\r
249     { "NOFLSH",      57, TTY_OP_BOOL },\r
250     { "TOSTOP",      58, TTY_OP_BOOL },\r
251     { "IEXTEN",      59, TTY_OP_BOOL },\r
252     { "ECHOCTL",     60, TTY_OP_BOOL },\r
253     { "ECHOKE",      61, TTY_OP_BOOL },\r
254     { "PENDIN",      62, TTY_OP_BOOL }, /* XXX is this a real mode? */\r
255     { "OPOST",       70, TTY_OP_BOOL },\r
256     { "OLCUC",       71, TTY_OP_BOOL },\r
257     { "ONLCR",       72, TTY_OP_BOOL },\r
258     { "OCRNL",       73, TTY_OP_BOOL },\r
259     { "ONOCR",       74, TTY_OP_BOOL },\r
260     { "ONLRET",      75, TTY_OP_BOOL },\r
261     { "CS7",         90, TTY_OP_BOOL },\r
262     { "CS8",         91, TTY_OP_BOOL },\r
263     { "PARENB",      92, TTY_OP_BOOL },\r
264     { "PARODD",      93, TTY_OP_BOOL }\r
265 };\r
267 /* Miscellaneous other tty-related constants. */\r
268 #define SSH_TTY_OP_END            0\r
269 /* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */\r
270 #define SSH1_TTY_OP_ISPEED      192\r
271 #define SSH1_TTY_OP_OSPEED      193\r
272 #define SSH2_TTY_OP_ISPEED      128\r
273 #define SSH2_TTY_OP_OSPEED      129\r
275 /* Helper functions for parsing tty-related config. */\r
276 static unsigned int ssh_tty_parse_specchar(char *s)\r
278     unsigned int ret;\r
279     if (*s) {\r
280         char *next = NULL;\r
281         ret = ctrlparse(s, &next);\r
282         if (!next) ret = s[0];\r
283     } else {\r
284         ret = 255; /* special value meaning "don't set" */\r
285     }\r
286     return ret;\r
288 static unsigned int ssh_tty_parse_boolean(char *s)\r
290     if (stricmp(s, "yes") == 0 ||\r
291         stricmp(s, "on") == 0 ||\r
292         stricmp(s, "true") == 0 ||\r
293         stricmp(s, "+") == 0)\r
294         return 1; /* true */\r
295     else if (stricmp(s, "no") == 0 ||\r
296              stricmp(s, "off") == 0 ||\r
297              stricmp(s, "false") == 0 ||\r
298              stricmp(s, "-") == 0)\r
299         return 0; /* false */\r
300     else\r
301         return (atoi(s) != 0);\r
304 #define translate(x) if (type == x) return #x\r
305 #define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x\r
306 #define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x\r
307 static char *ssh1_pkt_type(int type)\r
309     translate(SSH1_MSG_DISCONNECT);\r
310     translate(SSH1_SMSG_PUBLIC_KEY);\r
311     translate(SSH1_CMSG_SESSION_KEY);\r
312     translate(SSH1_CMSG_USER);\r
313     translate(SSH1_CMSG_AUTH_RSA);\r
314     translate(SSH1_SMSG_AUTH_RSA_CHALLENGE);\r
315     translate(SSH1_CMSG_AUTH_RSA_RESPONSE);\r
316     translate(SSH1_CMSG_AUTH_PASSWORD);\r
317     translate(SSH1_CMSG_REQUEST_PTY);\r
318     translate(SSH1_CMSG_WINDOW_SIZE);\r
319     translate(SSH1_CMSG_EXEC_SHELL);\r
320     translate(SSH1_CMSG_EXEC_CMD);\r
321     translate(SSH1_SMSG_SUCCESS);\r
322     translate(SSH1_SMSG_FAILURE);\r
323     translate(SSH1_CMSG_STDIN_DATA);\r
324     translate(SSH1_SMSG_STDOUT_DATA);\r
325     translate(SSH1_SMSG_STDERR_DATA);\r
326     translate(SSH1_CMSG_EOF);\r
327     translate(SSH1_SMSG_EXIT_STATUS);\r
328     translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);\r
329     translate(SSH1_MSG_CHANNEL_OPEN_FAILURE);\r
330     translate(SSH1_MSG_CHANNEL_DATA);\r
331     translate(SSH1_MSG_CHANNEL_CLOSE);\r
332     translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);\r
333     translate(SSH1_SMSG_X11_OPEN);\r
334     translate(SSH1_CMSG_PORT_FORWARD_REQUEST);\r
335     translate(SSH1_MSG_PORT_OPEN);\r
336     translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING);\r
337     translate(SSH1_SMSG_AGENT_OPEN);\r
338     translate(SSH1_MSG_IGNORE);\r
339     translate(SSH1_CMSG_EXIT_CONFIRMATION);\r
340     translate(SSH1_CMSG_X11_REQUEST_FORWARDING);\r
341     translate(SSH1_CMSG_AUTH_RHOSTS_RSA);\r
342     translate(SSH1_MSG_DEBUG);\r
343     translate(SSH1_CMSG_REQUEST_COMPRESSION);\r
344     translate(SSH1_CMSG_AUTH_TIS);\r
345     translate(SSH1_SMSG_AUTH_TIS_CHALLENGE);\r
346     translate(SSH1_CMSG_AUTH_TIS_RESPONSE);\r
347     translate(SSH1_CMSG_AUTH_CCARD);\r
348     translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE);\r
349     translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);\r
350     return "unknown";\r
352 static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)\r
354     translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);\r
355     translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);\r
356     translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI);\r
357     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI);\r
358     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI);\r
359     translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);\r
360     translate(SSH2_MSG_DISCONNECT);\r
361     translate(SSH2_MSG_IGNORE);\r
362     translate(SSH2_MSG_UNIMPLEMENTED);\r
363     translate(SSH2_MSG_DEBUG);\r
364     translate(SSH2_MSG_SERVICE_REQUEST);\r
365     translate(SSH2_MSG_SERVICE_ACCEPT);\r
366     translate(SSH2_MSG_KEXINIT);\r
367     translate(SSH2_MSG_NEWKEYS);\r
368     translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);\r
369     translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);\r
370     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);\r
371     translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);\r
372     translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);\r
373     translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);\r
374     translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);\r
375     translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);\r
376     translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);\r
377     translate(SSH2_MSG_USERAUTH_REQUEST);\r
378     translate(SSH2_MSG_USERAUTH_FAILURE);\r
379     translate(SSH2_MSG_USERAUTH_SUCCESS);\r
380     translate(SSH2_MSG_USERAUTH_BANNER);\r
381     translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);\r
382     translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);\r
383     translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);\r
384     translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);\r
385     translate(SSH2_MSG_GLOBAL_REQUEST);\r
386     translate(SSH2_MSG_REQUEST_SUCCESS);\r
387     translate(SSH2_MSG_REQUEST_FAILURE);\r
388     translate(SSH2_MSG_CHANNEL_OPEN);\r
389     translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
390     translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
391     translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
392     translate(SSH2_MSG_CHANNEL_DATA);\r
393     translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);\r
394     translate(SSH2_MSG_CHANNEL_EOF);\r
395     translate(SSH2_MSG_CHANNEL_CLOSE);\r
396     translate(SSH2_MSG_CHANNEL_REQUEST);\r
397     translate(SSH2_MSG_CHANNEL_SUCCESS);\r
398     translate(SSH2_MSG_CHANNEL_FAILURE);\r
399     return "unknown";\r
401 #undef translate\r
402 #undef translatec\r
404 /* Enumeration values for fields in SSH-1 packets */\r
405 enum {\r
406     PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,\r
407     /* These values are for communicating relevant semantics of\r
408      * fields to the packet logging code. */\r
409     PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA\r
410 };\r
412 /*\r
413  * Coroutine mechanics for the sillier bits of the code. If these\r
414  * macros look impenetrable to you, you might find it helpful to\r
415  * read\r
416  * \r
417  *   http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\r
418  * \r
419  * which explains the theory behind these macros.\r
420  * \r
421  * In particular, if you are getting `case expression not constant'\r
422  * errors when building with MS Visual Studio, this is because MS's\r
423  * Edit and Continue debugging feature causes their compiler to\r
424  * violate ANSI C. To disable Edit and Continue debugging:\r
425  * \r
426  *  - right-click ssh.c in the FileView\r
427  *  - click Settings\r
428  *  - select the C/C++ tab and the General category\r
429  *  - under `Debug info:', select anything _other_ than `Program\r
430  *    Database for Edit and Continue'.\r
431  */\r
432 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;\r
433 #define crState(t) \\r
434     struct t *s; \\r
435     if (!ssh->t) ssh->t = snew(struct t); \\r
436     s = ssh->t;\r
437 #define crFinish(z)     } *crLine = 0; return (z); }\r
438 #define crFinishV       } *crLine = 0; return; }\r
439 #define crReturn(z)     \\r
440         do {\\r
441             *crLine =__LINE__; return (z); case __LINE__:;\\r
442         } while (0)\r
443 #define crReturnV       \\r
444         do {\\r
445             *crLine=__LINE__; return; case __LINE__:;\\r
446         } while (0)\r
447 #define crStop(z)       do{ *crLine = 0; return (z); }while(0)\r
448 #define crStopV         do{ *crLine = 0; return; }while(0)\r
449 #define crWaitUntil(c)  do { crReturn(0); } while (!(c))\r
450 #define crWaitUntilV(c) do { crReturnV; } while (!(c))\r
452 typedef struct ssh_tag *Ssh;\r
453 struct Packet;\r
455 static struct Packet *ssh1_pkt_init(int pkt_type);\r
456 static struct Packet *ssh2_pkt_init(int pkt_type);\r
457 static void ssh_pkt_ensure(struct Packet *, int length);\r
458 static void ssh_pkt_adddata(struct Packet *, void *data, int len);\r
459 static void ssh_pkt_addbyte(struct Packet *, unsigned char value);\r
460 static void ssh2_pkt_addbool(struct Packet *, unsigned char value);\r
461 static void ssh_pkt_adduint32(struct Packet *, unsigned long value);\r
462 static void ssh_pkt_addstring_start(struct Packet *);\r
463 static void ssh_pkt_addstring_str(struct Packet *, char *data);\r
464 static void ssh_pkt_addstring_data(struct Packet *, char *data, int len);\r
465 static void ssh_pkt_addstring(struct Packet *, char *data);\r
466 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);\r
467 static void ssh1_pkt_addmp(struct Packet *, Bignum b);\r
468 static void ssh2_pkt_addmp(struct Packet *, Bignum b);\r
469 static int ssh2_pkt_construct(Ssh, struct Packet *);\r
470 static void ssh2_pkt_send(Ssh, struct Packet *);\r
471 static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);\r
472 static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,\r
473                          struct Packet *pktin);\r
474 static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,\r
475                              struct Packet *pktin);\r
477 /*\r
478  * Buffer management constants. There are several of these for\r
479  * various different purposes:\r
480  * \r
481  *  - SSH1_BUFFER_LIMIT is the amount of backlog that must build up\r
482  *    on a local data stream before we throttle the whole SSH\r
483  *    connection (in SSH-1 only). Throttling the whole connection is\r
484  *    pretty drastic so we set this high in the hope it won't\r
485  *    happen very often.\r
486  * \r
487  *  - SSH_MAX_BACKLOG is the amount of backlog that must build up\r
488  *    on the SSH connection itself before we defensively throttle\r
489  *    _all_ local data streams. This is pretty drastic too (though\r
490  *    thankfully unlikely in SSH-2 since the window mechanism should\r
491  *    ensure that the server never has any need to throttle its end\r
492  *    of the connection), so we set this high as well.\r
493  * \r
494  *  - OUR_V2_WINSIZE is the maximum window size we present on SSH-2\r
495  *    channels.\r
496  *\r
497  *  - OUR_V2_BIGWIN is the window size we advertise for the only\r
498  *    channel in a simple connection.  It must be <= INT_MAX.\r
499  *\r
500  *  - OUR_V2_MAXPKT is the official "maximum packet size" we send\r
501  *    to the remote side. This actually has nothing to do with the\r
502  *    size of the _packet_, but is instead a limit on the amount\r
503  *    of data we're willing to receive in a single SSH2 channel\r
504  *    data message.\r
505  *\r
506  *  - OUR_V2_PACKETLIMIT is actually the maximum size of SSH\r
507  *    _packet_ we're prepared to cope with.  It must be a multiple\r
508  *    of the cipher block size, and must be at least 35000.\r
509  */\r
511 #define SSH1_BUFFER_LIMIT 32768\r
512 #define SSH_MAX_BACKLOG 32768\r
513 #define OUR_V2_WINSIZE 16384\r
514 #define OUR_V2_BIGWIN 0x7fffffff\r
515 #define OUR_V2_MAXPKT 0x4000UL\r
516 #define OUR_V2_PACKETLIMIT 0x9000UL\r
518 /* Maximum length of passwords/passphrases (arbitrary) */\r
519 #define SSH_MAX_PASSWORD_LEN 100\r
521 const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };\r
523 const static struct ssh_mac *macs[] = {\r
524     &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5\r
525 };\r
526 const static struct ssh_mac *buggymacs[] = {\r
527     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5\r
528 };\r
530 static void *ssh_comp_none_init(void)\r
532     return NULL;\r
534 static void ssh_comp_none_cleanup(void *handle)\r
537 static int ssh_comp_none_block(void *handle, unsigned char *block, int len,\r
538                                unsigned char **outblock, int *outlen)\r
540     return 0;\r
542 static int ssh_comp_none_disable(void *handle)\r
544     return 0;\r
546 const static struct ssh_compress ssh_comp_none = {\r
547     "none", NULL,\r
548     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
549     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
550     ssh_comp_none_disable, NULL\r
551 };\r
552 extern const struct ssh_compress ssh_zlib;\r
553 const static struct ssh_compress *compressions[] = {\r
554     &ssh_zlib, &ssh_comp_none\r
555 };\r
557 enum {                                 /* channel types */\r
558     CHAN_MAINSESSION,\r
559     CHAN_X11,\r
560     CHAN_AGENT,\r
561     CHAN_SOCKDATA,\r
562     CHAN_SOCKDATA_DORMANT              /* one the remote hasn't confirmed */\r
563 };\r
565 /*\r
566  * little structure to keep track of outstanding WINDOW_ADJUSTs\r
567  */\r
568 struct winadj {\r
569     struct winadj *next;\r
570     unsigned size;\r
571 };\r
573 /*\r
574  * 2-3-4 tree storing channels.\r
575  */\r
576 struct ssh_channel {\r
577     Ssh ssh;                           /* pointer back to main context */\r
578     unsigned remoteid, localid;\r
579     int type;\r
580     /* True if we opened this channel but server hasn't confirmed. */\r
581     int halfopen;\r
582     /*\r
583      * In SSH-1, this value contains four bits:\r
584      * \r
585      *   1   We have sent SSH1_MSG_CHANNEL_CLOSE.\r
586      *   2   We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
587      *   4   We have received SSH1_MSG_CHANNEL_CLOSE.\r
588      *   8   We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
589      * \r
590      * A channel is completely finished with when all four bits are set.\r
591      */\r
592     int closes;\r
594     /*\r
595      * This flag indicates that a close is pending on the outgoing\r
596      * side of the channel: that is, wherever we're getting the data\r
597      * for this channel has sent us some data followed by EOF. We\r
598      * can't actually close the channel until we've finished sending\r
599      * the data, so we set this flag instead to remind us to\r
600      * initiate the closing process once our buffer is clear.\r
601      */\r
602     int pending_close;\r
604     /*\r
605      * True if this channel is causing the underlying connection to be\r
606      * throttled.\r
607      */\r
608     int throttling_conn;\r
609     union {\r
610         struct ssh2_data_channel {\r
611             bufchain outbuffer;\r
612             unsigned remwindow, remmaxpkt;\r
613             /* locwindow is signed so we can cope with excess data. */\r
614             int locwindow, locmaxwin;\r
615             /*\r
616              * remlocwin is the amount of local window that we think\r
617              * the remote end had available to it after it sent the\r
618              * last data packet or window adjust ack.\r
619              */\r
620             int remlocwin;\r
621             /*\r
622              * These store the list of window adjusts that haven't\r
623              * been acked.\r
624              */\r
625             struct winadj *winadj_head, *winadj_tail;\r
626             enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state;\r
627         } v2;\r
628     } v;\r
629     union {\r
630         struct ssh_agent_channel {\r
631             unsigned char *message;\r
632             unsigned char msglen[4];\r
633             unsigned lensofar, totallen;\r
634         } a;\r
635         struct ssh_x11_channel {\r
636             Socket s;\r
637         } x11;\r
638         struct ssh_pfd_channel {\r
639             Socket s;\r
640         } pfd;\r
641     } u;\r
642 };\r
644 /*\r
645  * 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2\r
646  * use this structure in different ways, reflecting SSH-2's\r
647  * altogether saner approach to port forwarding.\r
648  * \r
649  * In SSH-1, you arrange a remote forwarding by sending the server\r
650  * the remote port number, and the local destination host:port.\r
651  * When a connection comes in, the server sends you back that\r
652  * host:port pair, and you connect to it. This is a ready-made\r
653  * security hole if you're not on the ball: a malicious server\r
654  * could send you back _any_ host:port pair, so if you trustingly\r
655  * connect to the address it gives you then you've just opened the\r
656  * entire inside of your corporate network just by connecting\r
657  * through it to a dodgy SSH server. Hence, we must store a list of\r
658  * host:port pairs we _are_ trying to forward to, and reject a\r
659  * connection request from the server if it's not in the list.\r
660  * \r
661  * In SSH-2, each side of the connection minds its own business and\r
662  * doesn't send unnecessary information to the other. You arrange a\r
663  * remote forwarding by sending the server just the remote port\r
664  * number. When a connection comes in, the server tells you which\r
665  * of its ports was connected to; and _you_ have to remember what\r
666  * local host:port pair went with that port number.\r
667  * \r
668  * Hence, in SSH-1 this structure is indexed by destination\r
669  * host:port pair, whereas in SSH-2 it is indexed by source port.\r
670  */\r
671 struct ssh_portfwd; /* forward declaration */\r
673 struct ssh_rportfwd {\r
674     unsigned sport, dport;\r
675     char dhost[256];\r
676     char *sportdesc;\r
677     struct ssh_portfwd *pfrec;\r
678 };\r
679 #define free_rportfwd(pf) ( \\r
680     ((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) )\r
682 /*\r
683  * Separately to the rportfwd tree (which is for looking up port\r
684  * open requests from the server), a tree of _these_ structures is\r
685  * used to keep track of all the currently open port forwardings,\r
686  * so that we can reconfigure in mid-session if the user requests\r
687  * it.\r
688  */\r
689 struct ssh_portfwd {\r
690     enum { DESTROY, KEEP, CREATE } status;\r
691     int type;\r
692     unsigned sport, dport;\r
693     char *saddr, *daddr;\r
694     char *sserv, *dserv;\r
695     struct ssh_rportfwd *remote;\r
696     int addressfamily;\r
697     void *local;\r
698 };\r
699 #define free_portfwd(pf) ( \\r
700     ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \\r
701              sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )\r
703 struct Packet {\r
704     long length;            /* length of `data' actually used */\r
705     long forcepad;          /* SSH-2: force padding to at least this length */\r
706     int type;               /* only used for incoming packets */\r
707     unsigned long sequence; /* SSH-2 incoming sequence number */\r
708     unsigned char *data;    /* allocated storage */\r
709     unsigned char *body;    /* offset of payload within `data' */\r
710     long savedpos;          /* temporary index into `data' (for strings) */\r
711     long maxlen;            /* amount of storage allocated for `data' */\r
712     long encrypted_len;     /* for SSH-2 total-size counting */\r
714     /*\r
715      * State associated with packet logging\r
716      */\r
717     int logmode;\r
718     int nblanks;\r
719     struct logblank_t *blanks;\r
720 };\r
722 static void ssh1_protocol(Ssh ssh, void *vin, int inlen,\r
723                           struct Packet *pktin);\r
724 static void ssh2_protocol(Ssh ssh, void *vin, int inlen,\r
725                           struct Packet *pktin);\r
726 static void ssh1_protocol_setup(Ssh ssh);\r
727 static void ssh2_protocol_setup(Ssh ssh);\r
728 static void ssh_size(void *handle, int width, int height);\r
729 static void ssh_special(void *handle, Telnet_Special);\r
730 static int ssh2_try_send(struct ssh_channel *c);\r
731 static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len);\r
732 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);\r
733 static void ssh2_set_window(struct ssh_channel *c, int newwin);\r
734 static int ssh_sendbuffer(void *handle);\r
735 static int ssh_do_close(Ssh ssh, int notify_exit);\r
736 static unsigned long ssh_pkt_getuint32(struct Packet *pkt);\r
737 static int ssh2_pkt_getbool(struct Packet *pkt);\r
738 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);\r
739 static void ssh2_timer(void *ctx, long now);\r
740 static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,\r
741                              struct Packet *pktin);\r
743 struct rdpkt1_state_tag {\r
744     long len, pad, biglen, to_read;\r
745     unsigned long realcrc, gotcrc;\r
746     unsigned char *p;\r
747     int i;\r
748     int chunk;\r
749     struct Packet *pktin;\r
750 };\r
752 struct rdpkt2_state_tag {\r
753     long len, pad, payload, packetlen, maclen;\r
754     int i;\r
755     int cipherblk;\r
756     unsigned long incoming_sequence;\r
757     struct Packet *pktin;\r
758 };\r
760 typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);\r
761 typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);\r
763 struct queued_handler;\r
764 struct queued_handler {\r
765     int msg1, msg2;\r
766     chandler_fn_t handler;\r
767     void *ctx;\r
768     struct queued_handler *next;\r
769 };\r
771 struct ssh_tag {\r
772     const struct plug_function_table *fn;\r
773     /* the above field _must_ be first in the structure */\r
775     char *v_c, *v_s;\r
776     void *exhash;\r
778     Socket s;\r
780     void *ldisc;\r
781     void *logctx;\r
783     unsigned char session_key[32];\r
784     int v1_compressing;\r
785     int v1_remote_protoflags;\r
786     int v1_local_protoflags;\r
787     int agentfwd_enabled;\r
788     int X11_fwd_enabled;\r
789     int remote_bugs;\r
790     const struct ssh_cipher *cipher;\r
791     void *v1_cipher_ctx;\r
792     void *crcda_ctx;\r
793     const struct ssh2_cipher *cscipher, *sccipher;\r
794     void *cs_cipher_ctx, *sc_cipher_ctx;\r
795     const struct ssh_mac *csmac, *scmac;\r
796     void *cs_mac_ctx, *sc_mac_ctx;\r
797     const struct ssh_compress *cscomp, *sccomp;\r
798     void *cs_comp_ctx, *sc_comp_ctx;\r
799     const struct ssh_kex *kex;\r
800     const struct ssh_signkey *hostkey;\r
801     unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN];\r
802     int v2_session_id_len;\r
803     void *kex_ctx;\r
805     char *savedhost;\r
806     int savedport;\r
807     int send_ok;\r
808     int echoing, editing;\r
810     void *frontend;\r
812     int ospeed, ispeed;                /* temporaries */\r
813     int term_width, term_height;\r
815     tree234 *channels;                 /* indexed by local id */\r
816     struct ssh_channel *mainchan;      /* primary session channel */\r
817     int ncmode;                        /* is primary channel direct-tcpip? */\r
818     int exitcode;\r
819     int close_expected;\r
820     int clean_exit;\r
822     tree234 *rportfwds, *portfwds;\r
824     enum {\r
825         SSH_STATE_PREPACKET,\r
826         SSH_STATE_BEFORE_SIZE,\r
827         SSH_STATE_INTERMED,\r
828         SSH_STATE_SESSION,\r
829         SSH_STATE_CLOSED\r
830     } state;\r
832     int size_needed, eof_needed;\r
834     struct Packet **queue;\r
835     int queuelen, queuesize;\r
836     int queueing;\r
837     unsigned char *deferred_send_data;\r
838     int deferred_len, deferred_size;\r
840     /*\r
841      * Gross hack: pscp will try to start SFTP but fall back to\r
842      * scp1 if that fails. This variable is the means by which\r
843      * scp.c can reach into the SSH code and find out which one it\r
844      * got.\r
845      */\r
846     int fallback_cmd;\r
848     bufchain banner;    /* accumulates banners during do_ssh2_authconn */\r
850     Pkt_KCtx pkt_kctx;\r
851     Pkt_ACtx pkt_actx;\r
853     struct X11Display *x11disp;\r
855     int version;\r
856     int conn_throttle_count;\r
857     int overall_bufsize;\r
858     int throttled_all;\r
859     int v1_stdout_throttling;\r
860     unsigned long v2_outgoing_sequence;\r
862     int ssh1_rdpkt_crstate;\r
863     int ssh2_rdpkt_crstate;\r
864     int do_ssh_init_crstate;\r
865     int ssh_gotdata_crstate;\r
866     int do_ssh1_login_crstate;\r
867     int do_ssh1_connection_crstate;\r
868     int do_ssh2_transport_crstate;\r
869     int do_ssh2_authconn_crstate;\r
871     void *do_ssh_init_state;\r
872     void *do_ssh1_login_state;\r
873     void *do_ssh2_transport_state;\r
874     void *do_ssh2_authconn_state;\r
876     struct rdpkt1_state_tag rdpkt1_state;\r
877     struct rdpkt2_state_tag rdpkt2_state;\r
879     /* SSH-1 and SSH-2 use this for different things, but both use it */\r
880     int protocol_initial_phase_done;\r
882     void (*protocol) (Ssh ssh, void *vin, int inlen,\r
883                       struct Packet *pkt);\r
884     struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen);\r
886     /*\r
887      * We maintain a full _copy_ of a Config structure here, not\r
888      * merely a pointer to it. That way, when we're passed a new\r
889      * one for reconfiguration, we can check the differences and\r
890      * potentially reconfigure port forwardings etc in mid-session.\r
891      */\r
892     Config cfg;\r
894     /*\r
895      * Used to transfer data back from async callbacks.\r
896      */\r
897     void *agent_response;\r
898     int agent_response_len;\r
899     int user_response;\r
901     /*\r
902      * The SSH connection can be set as `frozen', meaning we are\r
903      * not currently accepting incoming data from the network. This\r
904      * is slightly more serious than setting the _socket_ as\r
905      * frozen, because we may already have had data passed to us\r
906      * from the network which we need to delay processing until\r
907      * after the freeze is lifted, so we also need a bufchain to\r
908      * store that data.\r
909      */\r
910     int frozen;\r
911     bufchain queued_incoming_data;\r
913     /*\r
914      * Dispatch table for packet types that we may have to deal\r
915      * with at any time.\r
916      */\r
917     handler_fn_t packet_dispatch[256];\r
919     /*\r
920      * Queues of one-off handler functions for success/failure\r
921      * indications from a request.\r
922      */\r
923     struct queued_handler *qhead, *qtail;\r
925     /*\r
926      * This module deals with sending keepalives.\r
927      */\r
928     Pinger pinger;\r
930     /*\r
931      * Track incoming and outgoing data sizes and time, for\r
932      * size-based rekeys.\r
933      */\r
934     unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;\r
935     unsigned long max_data_size;\r
936     int kex_in_progress;\r
937     long next_rekey, last_rekey;\r
938     char *deferred_rekey_reason;    /* points to STATIC string; don't free */\r
940     /*\r
941      * Fully qualified host name, which we need if doing GSSAPI.\r
942      */\r
943     char *fullhostname;\r
945 #ifndef NO_GSSAPI\r
946     /*\r
947      * GSSAPI libraries for this session.\r
948      */\r
949     struct ssh_gss_liblist *gsslibs;\r
950 #endif\r
951 };\r
953 #define logevent(s) logevent(ssh->frontend, s)\r
955 /* logevent, only printf-formatted. */\r
956 static void logeventf(Ssh ssh, const char *fmt, ...)\r
958     va_list ap;\r
959     char *buf;\r
961     va_start(ap, fmt);\r
962     buf = dupvprintf(fmt, ap);\r
963     va_end(ap);\r
964     logevent(buf);\r
965     sfree(buf);\r
968 #define bombout(msg) \\r
969     do { \\r
970         char *text = dupprintf msg; \\r
971         ssh_do_close(ssh, FALSE); \\r
972         logevent(text); \\r
973         connection_fatal(ssh->frontend, "%s", text); \\r
974         sfree(text); \\r
975     } while (0)\r
977 /* Functions to leave bits out of the SSH packet log file. */\r
979 static void dont_log_password(Ssh ssh, struct Packet *pkt, int blanktype)\r
981     if (ssh->cfg.logomitpass)\r
982         pkt->logmode = blanktype;\r
985 static void dont_log_data(Ssh ssh, struct Packet *pkt, int blanktype)\r
987     if (ssh->cfg.logomitdata)\r
988         pkt->logmode = blanktype;\r
991 static void end_log_omission(Ssh ssh, struct Packet *pkt)\r
993     pkt->logmode = PKTLOG_EMIT;\r
996 /* Helper function for common bits of parsing cfg.ttymodes. */\r
997 static void parse_ttymodes(Ssh ssh, char *modes,\r
998                            void (*do_mode)(void *data, char *mode, char *val),\r
999                            void *data)\r
1001     while (*modes) {\r
1002         char *t = strchr(modes, '\t');\r
1003         char *m = snewn(t-modes+1, char);\r
1004         char *val;\r
1005         strncpy(m, modes, t-modes);\r
1006         m[t-modes] = '\0';\r
1007         if (*(t+1) == 'A')\r
1008             val = get_ttymode(ssh->frontend, m);\r
1009         else\r
1010             val = dupstr(t+2);\r
1011         if (val)\r
1012             do_mode(data, m, val);\r
1013         sfree(m);\r
1014         sfree(val);\r
1015         modes += strlen(modes) + 1;\r
1016     }\r
1019 static int ssh_channelcmp(void *av, void *bv)\r
1021     struct ssh_channel *a = (struct ssh_channel *) av;\r
1022     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1023     if (a->localid < b->localid)\r
1024         return -1;\r
1025     if (a->localid > b->localid)\r
1026         return +1;\r
1027     return 0;\r
1029 static int ssh_channelfind(void *av, void *bv)\r
1031     unsigned *a = (unsigned *) av;\r
1032     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1033     if (*a < b->localid)\r
1034         return -1;\r
1035     if (*a > b->localid)\r
1036         return +1;\r
1037     return 0;\r
1040 static int ssh_rportcmp_ssh1(void *av, void *bv)\r
1042     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1043     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1044     int i;\r
1045     if ( (i = strcmp(a->dhost, b->dhost)) != 0)\r
1046         return i < 0 ? -1 : +1;\r
1047     if (a->dport > b->dport)\r
1048         return +1;\r
1049     if (a->dport < b->dport)\r
1050         return -1;\r
1051     return 0;\r
1054 static int ssh_rportcmp_ssh2(void *av, void *bv)\r
1056     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1057     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1059     if (a->sport > b->sport)\r
1060         return +1;\r
1061     if (a->sport < b->sport)\r
1062         return -1;\r
1063     return 0;\r
1066 /*\r
1067  * Special form of strcmp which can cope with NULL inputs. NULL is\r
1068  * defined to sort before even the empty string.\r
1069  */\r
1070 static int nullstrcmp(const char *a, const char *b)\r
1072     if (a == NULL && b == NULL)\r
1073         return 0;\r
1074     if (a == NULL)\r
1075         return -1;\r
1076     if (b == NULL)\r
1077         return +1;\r
1078     return strcmp(a, b);\r
1081 static int ssh_portcmp(void *av, void *bv)\r
1083     struct ssh_portfwd *a = (struct ssh_portfwd *) av;\r
1084     struct ssh_portfwd *b = (struct ssh_portfwd *) bv;\r
1085     int i;\r
1086     if (a->type > b->type)\r
1087         return +1;\r
1088     if (a->type < b->type)\r
1089         return -1;\r
1090     if (a->addressfamily > b->addressfamily)\r
1091         return +1;\r
1092     if (a->addressfamily < b->addressfamily)\r
1093         return -1;\r
1094     if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)\r
1095         return i < 0 ? -1 : +1;\r
1096     if (a->sport > b->sport)\r
1097         return +1;\r
1098     if (a->sport < b->sport)\r
1099         return -1;\r
1100     if (a->type != 'D') {\r
1101         if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)\r
1102             return i < 0 ? -1 : +1;\r
1103         if (a->dport > b->dport)\r
1104             return +1;\r
1105         if (a->dport < b->dport)\r
1106             return -1;\r
1107     }\r
1108     return 0;\r
1111 static int alloc_channel_id(Ssh ssh)\r
1113     const unsigned CHANNEL_NUMBER_OFFSET = 256;\r
1114     unsigned low, high, mid;\r
1115     int tsize;\r
1116     struct ssh_channel *c;\r
1118     /*\r
1119      * First-fit allocation of channel numbers: always pick the\r
1120      * lowest unused one. To do this, binary-search using the\r
1121      * counted B-tree to find the largest channel ID which is in a\r
1122      * contiguous sequence from the beginning. (Precisely\r
1123      * everything in that sequence must have ID equal to its tree\r
1124      * index plus CHANNEL_NUMBER_OFFSET.)\r
1125      */\r
1126     tsize = count234(ssh->channels);\r
1128     low = -1;\r
1129     high = tsize;\r
1130     while (high - low > 1) {\r
1131         mid = (high + low) / 2;\r
1132         c = index234(ssh->channels, mid);\r
1133         if (c->localid == mid + CHANNEL_NUMBER_OFFSET)\r
1134             low = mid;                 /* this one is fine */\r
1135         else\r
1136             high = mid;                /* this one is past it */\r
1137     }\r
1138     /*\r
1139      * Now low points to either -1, or the tree index of the\r
1140      * largest ID in the initial sequence.\r
1141      */\r
1142     {\r
1143         unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;\r
1144         assert(NULL == find234(ssh->channels, &i, ssh_channelfind));\r
1145     }\r
1146     return low + 1 + CHANNEL_NUMBER_OFFSET;\r
1149 static void c_write_stderr(int trusted, const char *buf, int len)\r
1151     int i;\r
1152     for (i = 0; i < len; i++)\r
1153         if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60)))\r
1154             fputc(buf[i], stderr);\r
1157 static void c_write(Ssh ssh, const char *buf, int len)\r
1159     if (flags & FLAG_STDERR)\r
1160         c_write_stderr(1, buf, len);\r
1161     else\r
1162         from_backend(ssh->frontend, 1, buf, len);\r
1165 static void c_write_untrusted(Ssh ssh, const char *buf, int len)\r
1167     if (flags & FLAG_STDERR)\r
1168         c_write_stderr(0, buf, len);\r
1169     else\r
1170         from_backend_untrusted(ssh->frontend, buf, len);\r
1173 static void c_write_str(Ssh ssh, const char *buf)\r
1175     c_write(ssh, buf, strlen(buf));\r
1178 static void ssh_free_packet(struct Packet *pkt)\r
1180     sfree(pkt->data);\r
1181     sfree(pkt);\r
1183 static struct Packet *ssh_new_packet(void)\r
1185     struct Packet *pkt = snew(struct Packet);\r
1187     pkt->body = pkt->data = NULL;\r
1188     pkt->maxlen = 0;\r
1189     pkt->logmode = PKTLOG_EMIT;\r
1190     pkt->nblanks = 0;\r
1191     pkt->blanks = NULL;\r
1193     return pkt;\r
1196 /*\r
1197  * Collect incoming data in the incoming packet buffer.\r
1198  * Decipher and verify the packet when it is completely read.\r
1199  * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.\r
1200  * Update the *data and *datalen variables.\r
1201  * Return a Packet structure when a packet is completed.\r
1202  */\r
1203 static struct Packet *ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)\r
1205     struct rdpkt1_state_tag *st = &ssh->rdpkt1_state;\r
1207     crBegin(ssh->ssh1_rdpkt_crstate);\r
1209     st->pktin = ssh_new_packet();\r
1211     st->pktin->type = 0;\r
1212     st->pktin->length = 0;\r
1214     for (st->i = st->len = 0; st->i < 4; st->i++) {\r
1215         while ((*datalen) == 0)\r
1216             crReturn(NULL);\r
1217         st->len = (st->len << 8) + **data;\r
1218         (*data)++, (*datalen)--;\r
1219     }\r
1221     st->pad = 8 - (st->len % 8);\r
1222     st->biglen = st->len + st->pad;\r
1223     st->pktin->length = st->len - 5;\r
1225     if (st->biglen < 0) {\r
1226         bombout(("Extremely large packet length from server suggests"\r
1227                  " data stream corruption"));\r
1228         ssh_free_packet(st->pktin);\r
1229         crStop(NULL);\r
1230     }\r
1232     st->pktin->maxlen = st->biglen;\r
1233     st->pktin->data = snewn(st->biglen + APIEXTRA, unsigned char);\r
1235     st->to_read = st->biglen;\r
1236     st->p = st->pktin->data;\r
1237     while (st->to_read > 0) {\r
1238         st->chunk = st->to_read;\r
1239         while ((*datalen) == 0)\r
1240             crReturn(NULL);\r
1241         if (st->chunk > (*datalen))\r
1242             st->chunk = (*datalen);\r
1243         memcpy(st->p, *data, st->chunk);\r
1244         *data += st->chunk;\r
1245         *datalen -= st->chunk;\r
1246         st->p += st->chunk;\r
1247         st->to_read -= st->chunk;\r
1248     }\r
1250     if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data,\r
1251                                      st->biglen, NULL)) {\r
1252         bombout(("Network attack (CRC compensation) detected!"));\r
1253         ssh_free_packet(st->pktin);\r
1254         crStop(NULL);\r
1255     }\r
1257     if (ssh->cipher)\r
1258         ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen);\r
1260     st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4);\r
1261     st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4);\r
1262     if (st->gotcrc != st->realcrc) {\r
1263         bombout(("Incorrect CRC received on packet"));\r
1264         ssh_free_packet(st->pktin);\r
1265         crStop(NULL);\r
1266     }\r
1268     st->pktin->body = st->pktin->data + st->pad + 1;\r
1269     st->pktin->savedpos = 0;\r
1271     if (ssh->v1_compressing) {\r
1272         unsigned char *decompblk;\r
1273         int decomplen;\r
1274         if (!zlib_decompress_block(ssh->sc_comp_ctx,\r
1275                                    st->pktin->body - 1, st->pktin->length + 1,\r
1276                                    &decompblk, &decomplen)) {\r
1277             bombout(("Zlib decompression encountered invalid data"));\r
1278             ssh_free_packet(st->pktin);\r
1279             crStop(NULL);\r
1280         }\r
1282         if (st->pktin->maxlen < st->pad + decomplen) {\r
1283             st->pktin->maxlen = st->pad + decomplen;\r
1284             st->pktin->data = sresize(st->pktin->data,\r
1285                                       st->pktin->maxlen + APIEXTRA,\r
1286                                       unsigned char);\r
1287             st->pktin->body = st->pktin->data + st->pad + 1;\r
1288         }\r
1290         memcpy(st->pktin->body - 1, decompblk, decomplen);\r
1291         sfree(decompblk);\r
1292         st->pktin->length = decomplen - 1;\r
1293     }\r
1295     st->pktin->type = st->pktin->body[-1];\r
1297     /*\r
1298      * Log incoming packet, possibly omitting sensitive fields.\r
1299      */\r
1300     if (ssh->logctx) {\r
1301         int nblanks = 0;\r
1302         struct logblank_t blank;\r
1303         if (ssh->cfg.logomitdata) {\r
1304             int do_blank = FALSE, blank_prefix = 0;\r
1305             /* "Session data" packets - omit the data field */\r
1306             if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) ||\r
1307                 (st->pktin->type == SSH1_SMSG_STDERR_DATA)) {\r
1308                 do_blank = TRUE; blank_prefix = 4;\r
1309             } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {\r
1310                 do_blank = TRUE; blank_prefix = 8;\r
1311             }\r
1312             if (do_blank) {\r
1313                 blank.offset = blank_prefix;\r
1314                 blank.len = st->pktin->length;\r
1315                 blank.type = PKTLOG_OMIT;\r
1316                 nblanks = 1;\r
1317             }\r
1318         }\r
1319         log_packet(ssh->logctx,\r
1320                    PKT_INCOMING, st->pktin->type,\r
1321                    ssh1_pkt_type(st->pktin->type),\r
1322                    st->pktin->body, st->pktin->length,\r
1323                    nblanks, &blank, NULL);\r
1324     }\r
1326     crFinish(st->pktin);\r
1329 static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)\r
1331     struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;\r
1333     crBegin(ssh->ssh2_rdpkt_crstate);\r
1335     st->pktin = ssh_new_packet();\r
1337     st->pktin->type = 0;\r
1338     st->pktin->length = 0;\r
1339     if (ssh->sccipher)\r
1340         st->cipherblk = ssh->sccipher->blksize;\r
1341     else\r
1342         st->cipherblk = 8;\r
1343     if (st->cipherblk < 8)\r
1344         st->cipherblk = 8;\r
1345     st->maclen = ssh->scmac ? ssh->scmac->len : 0;\r
1347     if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&\r
1348         ssh->scmac) {\r
1349         /*\r
1350          * When dealing with a CBC-mode cipher, we want to avoid the\r
1351          * possibility of an attacker's tweaking the ciphertext stream\r
1352          * so as to cause us to feed the same block to the block\r
1353          * cipher more than once and thus leak information\r
1354          * (VU#958563).  The way we do this is not to take any\r
1355          * decisions on the basis of anything we've decrypted until\r
1356          * we've verified it with a MAC.  That includes the packet\r
1357          * length, so we just read data and check the MAC repeatedly,\r
1358          * and when the MAC passes, see if the length we've got is\r
1359          * plausible.\r
1360          */\r
1362         /* May as well allocate the whole lot now. */\r
1363         st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,\r
1364                                 unsigned char);\r
1366         /* Read an amount corresponding to the MAC. */\r
1367         for (st->i = 0; st->i < st->maclen; st->i++) {\r
1368             while ((*datalen) == 0)\r
1369                 crReturn(NULL);\r
1370             st->pktin->data[st->i] = *(*data)++;\r
1371             (*datalen)--;\r
1372         }\r
1374         st->packetlen = 0;\r
1375         {\r
1376             unsigned char seq[4];\r
1377             ssh->scmac->start(ssh->sc_mac_ctx);\r
1378             PUT_32BIT(seq, st->incoming_sequence);\r
1379             ssh->scmac->bytes(ssh->sc_mac_ctx, seq, 4);\r
1380         }\r
1382         for (;;) { /* Once around this loop per cipher block. */\r
1383             /* Read another cipher-block's worth, and tack it onto the end. */\r
1384             for (st->i = 0; st->i < st->cipherblk; st->i++) {\r
1385                 while ((*datalen) == 0)\r
1386                     crReturn(NULL);\r
1387                 st->pktin->data[st->packetlen+st->maclen+st->i] = *(*data)++;\r
1388                 (*datalen)--;\r
1389             }\r
1390             /* Decrypt one more block (a little further back in the stream). */\r
1391             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1392                                    st->pktin->data + st->packetlen,\r
1393                                    st->cipherblk);\r
1394             /* Feed that block to the MAC. */\r
1395             ssh->scmac->bytes(ssh->sc_mac_ctx,\r
1396                               st->pktin->data + st->packetlen, st->cipherblk);\r
1397             st->packetlen += st->cipherblk;\r
1398             /* See if that gives us a valid packet. */\r
1399             if (ssh->scmac->verresult(ssh->sc_mac_ctx,\r
1400                                       st->pktin->data + st->packetlen) &&\r
1401                 (st->len = GET_32BIT(st->pktin->data)) + 4 == st->packetlen)\r
1402                     break;\r
1403             if (st->packetlen >= OUR_V2_PACKETLIMIT) {\r
1404                 bombout(("No valid incoming packet found"));\r
1405                 ssh_free_packet(st->pktin);\r
1406                 crStop(NULL);\r
1407             }       \r
1408         }\r
1409         st->pktin->maxlen = st->packetlen + st->maclen;\r
1410         st->pktin->data = sresize(st->pktin->data,\r
1411                                   st->pktin->maxlen + APIEXTRA,\r
1412                                   unsigned char);\r
1413     } else {\r
1414         st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);\r
1416         /*\r
1417          * Acquire and decrypt the first block of the packet. This will\r
1418          * contain the length and padding details.\r
1419          */\r
1420         for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {\r
1421             while ((*datalen) == 0)\r
1422                 crReturn(NULL);\r
1423             st->pktin->data[st->i] = *(*data)++;\r
1424             (*datalen)--;\r
1425         }\r
1427         if (ssh->sccipher)\r
1428             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1429                                    st->pktin->data, st->cipherblk);\r
1431         /*\r
1432          * Now get the length figure.\r
1433          */\r
1434         st->len = GET_32BIT(st->pktin->data);\r
1436         /*\r
1437          * _Completely_ silly lengths should be stomped on before they\r
1438          * do us any more damage.\r
1439          */\r
1440         if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||\r
1441             (st->len + 4) % st->cipherblk != 0) {\r
1442             bombout(("Incoming packet was garbled on decryption"));\r
1443             ssh_free_packet(st->pktin);\r
1444             crStop(NULL);\r
1445         }\r
1447         /*\r
1448          * So now we can work out the total packet length.\r
1449          */\r
1450         st->packetlen = st->len + 4;\r
1452         /*\r
1453          * Allocate memory for the rest of the packet.\r
1454          */\r
1455         st->pktin->maxlen = st->packetlen + st->maclen;\r
1456         st->pktin->data = sresize(st->pktin->data,\r
1457                                   st->pktin->maxlen + APIEXTRA,\r
1458                                   unsigned char);\r
1460         /*\r
1461          * Read and decrypt the remainder of the packet.\r
1462          */\r
1463         for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;\r
1464              st->i++) {\r
1465             while ((*datalen) == 0)\r
1466                 crReturn(NULL);\r
1467             st->pktin->data[st->i] = *(*data)++;\r
1468             (*datalen)--;\r
1469         }\r
1470         /* Decrypt everything _except_ the MAC. */\r
1471         if (ssh->sccipher)\r
1472             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1473                                    st->pktin->data + st->cipherblk,\r
1474                                    st->packetlen - st->cipherblk);\r
1476         /*\r
1477          * Check the MAC.\r
1478          */\r
1479         if (ssh->scmac\r
1480             && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,\r
1481                                    st->len + 4, st->incoming_sequence)) {\r
1482             bombout(("Incorrect MAC received on packet"));\r
1483             ssh_free_packet(st->pktin);\r
1484             crStop(NULL);\r
1485         }\r
1486     }\r
1487     /* Get and sanity-check the amount of random padding. */\r
1488     st->pad = st->pktin->data[4];\r
1489     if (st->pad < 4 || st->len - st->pad < 1) {\r
1490         bombout(("Invalid padding length on received packet"));\r
1491         ssh_free_packet(st->pktin);\r
1492         crStop(NULL);\r
1493     }\r
1494     /*\r
1495      * This enables us to deduce the payload length.\r
1496      */\r
1497     st->payload = st->len - st->pad - 1;\r
1499     st->pktin->length = st->payload + 5;\r
1500     st->pktin->encrypted_len = st->packetlen;\r
1502     st->pktin->sequence = st->incoming_sequence++;\r
1504     /*\r
1505      * Decompress packet payload.\r
1506      */\r
1507     {\r
1508         unsigned char *newpayload;\r
1509         int newlen;\r
1510         if (ssh->sccomp &&\r
1511             ssh->sccomp->decompress(ssh->sc_comp_ctx,\r
1512                                     st->pktin->data + 5, st->pktin->length - 5,\r
1513                                     &newpayload, &newlen)) {\r
1514             if (st->pktin->maxlen < newlen + 5) {\r
1515                 st->pktin->maxlen = newlen + 5;\r
1516                 st->pktin->data = sresize(st->pktin->data,\r
1517                                           st->pktin->maxlen + APIEXTRA,\r
1518                                           unsigned char);\r
1519             }\r
1520             st->pktin->length = 5 + newlen;\r
1521             memcpy(st->pktin->data + 5, newpayload, newlen);\r
1522             sfree(newpayload);\r
1523         }\r
1524     }\r
1526     st->pktin->savedpos = 6;\r
1527     st->pktin->body = st->pktin->data;\r
1528     st->pktin->type = st->pktin->data[5];\r
1530     /*\r
1531      * Log incoming packet, possibly omitting sensitive fields.\r
1532      */\r
1533     if (ssh->logctx) {\r
1534         int nblanks = 0;\r
1535         struct logblank_t blank;\r
1536         if (ssh->cfg.logomitdata) {\r
1537             int do_blank = FALSE, blank_prefix = 0;\r
1538             /* "Session data" packets - omit the data field */\r
1539             if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) {\r
1540                 do_blank = TRUE; blank_prefix = 8;\r
1541             } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {\r
1542                 do_blank = TRUE; blank_prefix = 12;\r
1543             }\r
1544             if (do_blank) {\r
1545                 blank.offset = blank_prefix;\r
1546                 blank.len = (st->pktin->length-6) - blank_prefix;\r
1547                 blank.type = PKTLOG_OMIT;\r
1548                 nblanks = 1;\r
1549             }\r
1550         }\r
1551         log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type,\r
1552                    ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
1553                                  st->pktin->type),\r
1554                    st->pktin->data+6, st->pktin->length-6,\r
1555                    nblanks, &blank, &st->pktin->sequence);\r
1556     }\r
1558     crFinish(st->pktin);\r
1561 static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p)\r
1563     int pad, biglen, i, pktoffs;\r
1564     unsigned long crc;\r
1565 #ifdef __SC__\r
1566     /*\r
1567      * XXX various versions of SC (including 8.8.4) screw up the\r
1568      * register allocation in this function and use the same register\r
1569      * (D6) for len and as a temporary, with predictable results.  The\r
1570      * following sledgehammer prevents this.\r
1571      */\r
1572     volatile\r
1573 #endif\r
1574     int len;\r
1576     if (ssh->logctx)\r
1577         log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],\r
1578                    ssh1_pkt_type(pkt->data[12]),\r
1579                    pkt->body, pkt->length - (pkt->body - pkt->data),\r
1580                    pkt->nblanks, pkt->blanks, NULL);\r
1581     sfree(pkt->blanks); pkt->blanks = NULL;\r
1582     pkt->nblanks = 0;\r
1584     if (ssh->v1_compressing) {\r
1585         unsigned char *compblk;\r
1586         int complen;\r
1587         zlib_compress_block(ssh->cs_comp_ctx,\r
1588                             pkt->data + 12, pkt->length - 12,\r
1589                             &compblk, &complen);\r
1590         ssh_pkt_ensure(pkt, complen + 2);   /* just in case it's got bigger */\r
1591         memcpy(pkt->data + 12, compblk, complen);\r
1592         sfree(compblk);\r
1593         pkt->length = complen + 12;\r
1594     }\r
1596     ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */\r
1597     pkt->length += 4;\r
1598     len = pkt->length - 4 - 8;  /* len(type+data+CRC) */\r
1599     pad = 8 - (len % 8);\r
1600     pktoffs = 8 - pad;\r
1601     biglen = len + pad;         /* len(padding+type+data+CRC) */\r
1603     for (i = pktoffs; i < 4+8; i++)\r
1604         pkt->data[i] = random_byte();\r
1605     crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */\r
1606     PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);\r
1607     PUT_32BIT(pkt->data + pktoffs, len);\r
1609     if (ssh->cipher)\r
1610         ssh->cipher->encrypt(ssh->v1_cipher_ctx,\r
1611                              pkt->data + pktoffs + 4, biglen);\r
1613     if (offset_p) *offset_p = pktoffs;\r
1614     return biglen + 4;          /* len(length+padding+type+data+CRC) */\r
1617 static int s_write(Ssh ssh, void *data, int len)\r
1619     if (ssh->logctx)\r
1620         log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len,\r
1621                    0, NULL, NULL);\r
1622     return sk_write(ssh->s, (char *)data, len);\r
1625 static void s_wrpkt(Ssh ssh, struct Packet *pkt)\r
1627     int len, backlog, offset;\r
1628     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
1629     backlog = s_write(ssh, pkt->data + offset, len);\r
1630     if (backlog > SSH_MAX_BACKLOG)\r
1631         ssh_throttle_all(ssh, 1, backlog);\r
1632     ssh_free_packet(pkt);\r
1635 static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt)\r
1637     int len, offset;\r
1638     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
1639     if (ssh->deferred_len + len > ssh->deferred_size) {\r
1640         ssh->deferred_size = ssh->deferred_len + len + 128;\r
1641         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
1642                                           ssh->deferred_size,\r
1643                                           unsigned char);\r
1644     }\r
1645     memcpy(ssh->deferred_send_data + ssh->deferred_len,\r
1646            pkt->data + offset, len);\r
1647     ssh->deferred_len += len;\r
1648     ssh_free_packet(pkt);\r
1651 /*\r
1652  * Construct a SSH-1 packet with the specified contents.\r
1653  * (This all-at-once interface used to be the only one, but now SSH-1\r
1654  * packets can also be constructed incrementally.)\r
1655  */\r
1656 static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap)\r
1658     int argtype;\r
1659     Bignum bn;\r
1660     struct Packet *pkt;\r
1662     pkt = ssh1_pkt_init(pkttype);\r
1664     while ((argtype = va_arg(ap, int)) != PKT_END) {\r
1665         unsigned char *argp, argchar;\r
1666         char *sargp;\r
1667         unsigned long argint;\r
1668         int arglen;\r
1669         switch (argtype) {\r
1670           /* Actual fields in the packet */\r
1671           case PKT_INT:\r
1672             argint = va_arg(ap, int);\r
1673             ssh_pkt_adduint32(pkt, argint);\r
1674             break;\r
1675           case PKT_CHAR:\r
1676             argchar = (unsigned char) va_arg(ap, int);\r
1677             ssh_pkt_addbyte(pkt, argchar);\r
1678             break;\r
1679           case PKT_DATA:\r
1680             argp = va_arg(ap, unsigned char *);\r
1681             arglen = va_arg(ap, int);\r
1682             ssh_pkt_adddata(pkt, argp, arglen);\r
1683             break;\r
1684           case PKT_STR:\r
1685             sargp = va_arg(ap, char *);\r
1686             ssh_pkt_addstring(pkt, sargp);\r
1687             break;\r
1688           case PKT_BIGNUM:\r
1689             bn = va_arg(ap, Bignum);\r
1690             ssh1_pkt_addmp(pkt, bn);\r
1691             break;\r
1692           /* Tokens for modifications to packet logging */\r
1693           case PKTT_PASSWORD:\r
1694             dont_log_password(ssh, pkt, PKTLOG_BLANK);\r
1695             break;\r
1696           case PKTT_DATA:\r
1697             dont_log_data(ssh, pkt, PKTLOG_OMIT);\r
1698             break;\r
1699           case PKTT_OTHER:\r
1700             end_log_omission(ssh, pkt);\r
1701             break;\r
1702         }\r
1703     }\r
1705     return pkt;\r
1708 static void send_packet(Ssh ssh, int pkttype, ...)\r
1710     struct Packet *pkt;\r
1711     va_list ap;\r
1712     va_start(ap, pkttype);\r
1713     pkt = construct_packet(ssh, pkttype, ap);\r
1714     va_end(ap);\r
1715     s_wrpkt(ssh, pkt);\r
1718 static void defer_packet(Ssh ssh, int pkttype, ...)\r
1720     struct Packet *pkt;\r
1721     va_list ap;\r
1722     va_start(ap, pkttype);\r
1723     pkt = construct_packet(ssh, pkttype, ap);\r
1724     va_end(ap);\r
1725     s_wrpkt_defer(ssh, pkt);\r
1728 static int ssh_versioncmp(char *a, char *b)\r
1730     char *ae, *be;\r
1731     unsigned long av, bv;\r
1733     av = strtoul(a, &ae, 10);\r
1734     bv = strtoul(b, &be, 10);\r
1735     if (av != bv)\r
1736         return (av < bv ? -1 : +1);\r
1737     if (*ae == '.')\r
1738         ae++;\r
1739     if (*be == '.')\r
1740         be++;\r
1741     av = strtoul(ae, &ae, 10);\r
1742     bv = strtoul(be, &be, 10);\r
1743     if (av != bv)\r
1744         return (av < bv ? -1 : +1);\r
1745     return 0;\r
1748 /*\r
1749  * Utility routines for putting an SSH-protocol `string' and\r
1750  * `uint32' into a hash state.\r
1751  */\r
1752 static void hash_string(const struct ssh_hash *h, void *s, void *str, int len)\r
1754     unsigned char lenblk[4];\r
1755     PUT_32BIT(lenblk, len);\r
1756     h->bytes(s, lenblk, 4);\r
1757     h->bytes(s, str, len);\r
1760 static void hash_uint32(const struct ssh_hash *h, void *s, unsigned i)\r
1762     unsigned char intblk[4];\r
1763     PUT_32BIT(intblk, i);\r
1764     h->bytes(s, intblk, 4);\r
1767 /*\r
1768  * Packet construction functions. Mostly shared between SSH-1 and SSH-2.\r
1769  */\r
1770 static void ssh_pkt_ensure(struct Packet *pkt, int length)\r
1772     if (pkt->maxlen < length) {\r
1773         unsigned char *body = pkt->body;\r
1774         int offset = body ? body - pkt->data : 0;\r
1775         pkt->maxlen = length + 256;\r
1776         pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char);\r
1777         if (body) pkt->body = pkt->data + offset;\r
1778     }\r
1780 static void ssh_pkt_adddata(struct Packet *pkt, void *data, int len)\r
1782     if (pkt->logmode != PKTLOG_EMIT) {\r
1783         pkt->nblanks++;\r
1784         pkt->blanks = sresize(pkt->blanks, pkt->nblanks, struct logblank_t);\r
1785         assert(pkt->body);\r
1786         pkt->blanks[pkt->nblanks-1].offset = pkt->length -\r
1787                                              (pkt->body - pkt->data);\r
1788         pkt->blanks[pkt->nblanks-1].len = len;\r
1789         pkt->blanks[pkt->nblanks-1].type = pkt->logmode;\r
1790     }\r
1791     pkt->length += len;\r
1792     ssh_pkt_ensure(pkt, pkt->length);\r
1793     memcpy(pkt->data + pkt->length - len, data, len);\r
1795 static void ssh_pkt_addbyte(struct Packet *pkt, unsigned char byte)\r
1797     ssh_pkt_adddata(pkt, &byte, 1);\r
1799 static void ssh2_pkt_addbool(struct Packet *pkt, unsigned char value)\r
1801     ssh_pkt_adddata(pkt, &value, 1);\r
1803 static void ssh_pkt_adduint32(struct Packet *pkt, unsigned long value)\r
1805     unsigned char x[4];\r
1806     PUT_32BIT(x, value);\r
1807     ssh_pkt_adddata(pkt, x, 4);\r
1809 static void ssh_pkt_addstring_start(struct Packet *pkt)\r
1811     ssh_pkt_adduint32(pkt, 0);\r
1812     pkt->savedpos = pkt->length;\r
1814 static void ssh_pkt_addstring_str(struct Packet *pkt, char *data)\r
1816     ssh_pkt_adddata(pkt, data, strlen(data));\r
1817     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);\r
1819 static void ssh_pkt_addstring_data(struct Packet *pkt, char *data, int len)\r
1821     ssh_pkt_adddata(pkt, data, len);\r
1822     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);\r
1824 static void ssh_pkt_addstring(struct Packet *pkt, char *data)\r
1826     ssh_pkt_addstring_start(pkt);\r
1827     ssh_pkt_addstring_str(pkt, data);\r
1829 static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b)\r
1831     int len = ssh1_bignum_length(b);\r
1832     unsigned char *data = snewn(len, unsigned char);\r
1833     (void) ssh1_write_bignum(data, b);\r
1834     ssh_pkt_adddata(pkt, data, len);\r
1835     sfree(data);\r
1837 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)\r
1839     unsigned char *p;\r
1840     int i, n = (bignum_bitcount(b) + 7) / 8;\r
1841     p = snewn(n + 1, unsigned char);\r
1842     p[0] = 0;\r
1843     for (i = 1; i <= n; i++)\r
1844         p[i] = bignum_byte(b, n - i);\r
1845     i = 0;\r
1846     while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)\r
1847         i++;\r
1848     memmove(p, p + i, n + 1 - i);\r
1849     *len = n + 1 - i;\r
1850     return p;\r
1852 static void ssh2_pkt_addmp(struct Packet *pkt, Bignum b)\r
1854     unsigned char *p;\r
1855     int len;\r
1856     p = ssh2_mpint_fmt(b, &len);\r
1857     ssh_pkt_addstring_start(pkt);\r
1858     ssh_pkt_addstring_data(pkt, (char *)p, len);\r
1859     sfree(p);\r
1862 static struct Packet *ssh1_pkt_init(int pkt_type)\r
1864     struct Packet *pkt = ssh_new_packet();\r
1865     pkt->length = 4 + 8;            /* space for length + max padding */\r
1866     ssh_pkt_addbyte(pkt, pkt_type);\r
1867     pkt->body = pkt->data + pkt->length;\r
1868     return pkt;\r
1871 /* For legacy code (SSH-1 and -2 packet construction used to be separate) */\r
1872 #define ssh2_pkt_ensure(pkt, length) ssh_pkt_ensure(pkt, length)\r
1873 #define ssh2_pkt_adddata(pkt, data, len) ssh_pkt_adddata(pkt, data, len)\r
1874 #define ssh2_pkt_addbyte(pkt, byte) ssh_pkt_addbyte(pkt, byte)\r
1875 #define ssh2_pkt_adduint32(pkt, value) ssh_pkt_adduint32(pkt, value)\r
1876 #define ssh2_pkt_addstring_start(pkt) ssh_pkt_addstring_start(pkt)\r
1877 #define ssh2_pkt_addstring_str(pkt, data) ssh_pkt_addstring_str(pkt, data)\r
1878 #define ssh2_pkt_addstring_data(pkt, data, len) ssh_pkt_addstring_data(pkt, data, len)\r
1879 #define ssh2_pkt_addstring(pkt, data) ssh_pkt_addstring(pkt, data)\r
1881 static struct Packet *ssh2_pkt_init(int pkt_type)\r
1883     struct Packet *pkt = ssh_new_packet();\r
1884     pkt->length = 5; /* space for packet length + padding length */\r
1885     pkt->forcepad = 0;\r
1886     ssh_pkt_addbyte(pkt, (unsigned char) pkt_type);\r
1887     pkt->body = pkt->data + pkt->length; /* after packet type */\r
1888     return pkt;\r
1891 /*\r
1892  * Construct an SSH-2 final-form packet: compress it, encrypt it,\r
1893  * put the MAC on it. Final packet, ready to be sent, is stored in\r
1894  * pkt->data. Total length is returned.\r
1895  */\r
1896 static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt)\r
1898     int cipherblk, maclen, padding, i;\r
1900     if (ssh->logctx)\r
1901         log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],\r
1902                    ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),\r
1903                    pkt->body, pkt->length - (pkt->body - pkt->data),\r
1904                    pkt->nblanks, pkt->blanks, &ssh->v2_outgoing_sequence);\r
1905     sfree(pkt->blanks); pkt->blanks = NULL;\r
1906     pkt->nblanks = 0;\r
1908     /*\r
1909      * Compress packet payload.\r
1910      */\r
1911     {\r
1912         unsigned char *newpayload;\r
1913         int newlen;\r
1914         if (ssh->cscomp &&\r
1915             ssh->cscomp->compress(ssh->cs_comp_ctx, pkt->data + 5,\r
1916                                   pkt->length - 5,\r
1917                                   &newpayload, &newlen)) {\r
1918             pkt->length = 5;\r
1919             ssh2_pkt_adddata(pkt, newpayload, newlen);\r
1920             sfree(newpayload);\r
1921         }\r
1922     }\r
1924     /*\r
1925      * Add padding. At least four bytes, and must also bring total\r
1926      * length (minus MAC) up to a multiple of the block size.\r
1927      * If pkt->forcepad is set, make sure the packet is at least that size\r
1928      * after padding.\r
1929      */\r
1930     cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8;  /* block size */\r
1931     cipherblk = cipherblk < 8 ? 8 : cipherblk;  /* or 8 if blksize < 8 */\r
1932     padding = 4;\r
1933     if (pkt->length + padding < pkt->forcepad)\r
1934         padding = pkt->forcepad - pkt->length;\r
1935     padding +=\r
1936         (cipherblk - (pkt->length + padding) % cipherblk) % cipherblk;\r
1937     assert(padding <= 255);\r
1938     maclen = ssh->csmac ? ssh->csmac->len : 0;\r
1939     ssh2_pkt_ensure(pkt, pkt->length + padding + maclen);\r
1940     pkt->data[4] = padding;\r
1941     for (i = 0; i < padding; i++)\r
1942         pkt->data[pkt->length + i] = random_byte();\r
1943     PUT_32BIT(pkt->data, pkt->length + padding - 4);\r
1944     if (ssh->csmac)\r
1945         ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,\r
1946                              pkt->length + padding,\r
1947                              ssh->v2_outgoing_sequence);\r
1948     ssh->v2_outgoing_sequence++;       /* whether or not we MACed */\r
1950     if (ssh->cscipher)\r
1951         ssh->cscipher->encrypt(ssh->cs_cipher_ctx,\r
1952                                pkt->data, pkt->length + padding);\r
1954     pkt->encrypted_len = pkt->length + padding;\r
1956     /* Ready-to-send packet starts at pkt->data. We return length. */\r
1957     return pkt->length + padding + maclen;\r
1960 /*\r
1961  * Routines called from the main SSH code to send packets. There\r
1962  * are quite a few of these, because we have two separate\r
1963  * mechanisms for delaying the sending of packets:\r
1964  * \r
1965  *  - In order to send an IGNORE message and a password message in\r
1966  *    a single fixed-length blob, we require the ability to\r
1967  *    concatenate the encrypted forms of those two packets _into_ a\r
1968  *    single blob and then pass it to our <network.h> transport\r
1969  *    layer in one go. Hence, there's a deferment mechanism which\r
1970  *    works after packet encryption.\r
1971  * \r
1972  *  - In order to avoid sending any connection-layer messages\r
1973  *    during repeat key exchange, we have to queue up any such\r
1974  *    outgoing messages _before_ they are encrypted (and in\r
1975  *    particular before they're allocated sequence numbers), and\r
1976  *    then send them once we've finished.\r
1977  * \r
1978  * I call these mechanisms `defer' and `queue' respectively, so as\r
1979  * to distinguish them reasonably easily.\r
1980  * \r
1981  * The functions send_noqueue() and defer_noqueue() free the packet\r
1982  * structure they are passed. Every outgoing packet goes through\r
1983  * precisely one of these functions in its life; packets passed to\r
1984  * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of\r
1985  * these or get queued, and then when the queue is later emptied\r
1986  * the packets are all passed to defer_noqueue().\r
1987  *\r
1988  * When using a CBC-mode cipher, it's necessary to ensure that an\r
1989  * attacker can't provide data to be encrypted using an IV that they\r
1990  * know.  We ensure this by prefixing each packet that might contain\r
1991  * user data with an SSH_MSG_IGNORE.  This is done using the deferral\r
1992  * mechanism, so in this case send_noqueue() ends up redirecting to\r
1993  * defer_noqueue().  If you don't like this inefficiency, don't use\r
1994  * CBC.\r
1995  */\r
1997 static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int);\r
1998 static void ssh_pkt_defersend(Ssh);\r
2000 /*\r
2001  * Send an SSH-2 packet immediately, without queuing or deferring.\r
2002  */\r
2003 static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt)\r
2005     int len;\r
2006     int backlog;\r
2007     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) {\r
2008         /* We need to send two packets, so use the deferral mechanism. */\r
2009         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2010         ssh_pkt_defersend(ssh);\r
2011         return;\r
2012     }\r
2013     len = ssh2_pkt_construct(ssh, pkt);\r
2014     backlog = s_write(ssh, pkt->data, len);\r
2015     if (backlog > SSH_MAX_BACKLOG)\r
2016         ssh_throttle_all(ssh, 1, backlog);\r
2018     ssh->outgoing_data_size += pkt->encrypted_len;\r
2019     if (!ssh->kex_in_progress &&\r
2020         ssh->max_data_size != 0 &&\r
2021         ssh->outgoing_data_size > ssh->max_data_size)\r
2022         do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2024     ssh_free_packet(pkt);\r
2027 /*\r
2028  * Defer an SSH-2 packet.\r
2029  */\r
2030 static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore)\r
2032     int len;\r
2033     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) &&\r
2034         ssh->deferred_len == 0 && !noignore &&\r
2035         !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2036         /*\r
2037          * Interpose an SSH_MSG_IGNORE to ensure that user data don't\r
2038          * get encrypted with a known IV.\r
2039          */\r
2040         struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2041         ssh2_pkt_addstring_start(ipkt);\r
2042         ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE);\r
2043     }\r
2044     len = ssh2_pkt_construct(ssh, pkt);\r
2045     if (ssh->deferred_len + len > ssh->deferred_size) {\r
2046         ssh->deferred_size = ssh->deferred_len + len + 128;\r
2047         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
2048                                           ssh->deferred_size,\r
2049                                           unsigned char);\r
2050     }\r
2051     memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->data, len);\r
2052     ssh->deferred_len += len;\r
2053     ssh->deferred_data_size += pkt->encrypted_len;\r
2054     ssh_free_packet(pkt);\r
2057 /*\r
2058  * Queue an SSH-2 packet.\r
2059  */\r
2060 static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt)\r
2062     assert(ssh->queueing);\r
2064     if (ssh->queuelen >= ssh->queuesize) {\r
2065         ssh->queuesize = ssh->queuelen + 32;\r
2066         ssh->queue = sresize(ssh->queue, ssh->queuesize, struct Packet *);\r
2067     }\r
2069     ssh->queue[ssh->queuelen++] = pkt;\r
2072 /*\r
2073  * Either queue or send a packet, depending on whether queueing is\r
2074  * set.\r
2075  */\r
2076 static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt)\r
2078     if (ssh->queueing)\r
2079         ssh2_pkt_queue(ssh, pkt);\r
2080     else\r
2081         ssh2_pkt_send_noqueue(ssh, pkt);\r
2084 /*\r
2085  * Either queue or defer a packet, depending on whether queueing is\r
2086  * set.\r
2087  */\r
2088 static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt)\r
2090     if (ssh->queueing)\r
2091         ssh2_pkt_queue(ssh, pkt);\r
2092     else\r
2093         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2096 /*\r
2097  * Send the whole deferred data block constructed by\r
2098  * ssh2_pkt_defer() or SSH-1's defer_packet().\r
2099  * \r
2100  * The expected use of the defer mechanism is that you call\r
2101  * ssh2_pkt_defer() a few times, then call ssh_pkt_defersend(). If\r
2102  * not currently queueing, this simply sets up deferred_send_data\r
2103  * and then sends it. If we _are_ currently queueing, the calls to\r
2104  * ssh2_pkt_defer() put the deferred packets on to the queue\r
2105  * instead, and therefore ssh_pkt_defersend() has no deferred data\r
2106  * to send. Hence, there's no need to make it conditional on\r
2107  * ssh->queueing.\r
2108  */\r
2109 static void ssh_pkt_defersend(Ssh ssh)\r
2111     int backlog;\r
2112     backlog = s_write(ssh, ssh->deferred_send_data, ssh->deferred_len);\r
2113     ssh->deferred_len = ssh->deferred_size = 0;\r
2114     sfree(ssh->deferred_send_data);\r
2115     ssh->deferred_send_data = NULL;\r
2116     if (backlog > SSH_MAX_BACKLOG)\r
2117         ssh_throttle_all(ssh, 1, backlog);\r
2119     ssh->outgoing_data_size += ssh->deferred_data_size;\r
2120     if (!ssh->kex_in_progress &&\r
2121         ssh->max_data_size != 0 &&\r
2122         ssh->outgoing_data_size > ssh->max_data_size)\r
2123         do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2124     ssh->deferred_data_size = 0;\r
2127 /*\r
2128  * Send a packet whose length needs to be disguised (typically\r
2129  * passwords or keyboard-interactive responses).\r
2130  */\r
2131 static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt,\r
2132                                        int padsize)\r
2134 #if 0\r
2135     if (0) {\r
2136         /*\r
2137          * The simplest way to do this is to adjust the\r
2138          * variable-length padding field in the outgoing packet.\r
2139          * \r
2140          * Currently compiled out, because some Cisco SSH servers\r
2141          * don't like excessively padded packets (bah, why's it\r
2142          * always Cisco?)\r
2143          */\r
2144         pkt->forcepad = padsize;\r
2145         ssh2_pkt_send(ssh, pkt);\r
2146     } else\r
2147 #endif\r
2148     {\r
2149         /*\r
2150          * If we can't do that, however, an alternative approach is\r
2151          * to use the pkt_defer mechanism to bundle the packet\r
2152          * tightly together with an SSH_MSG_IGNORE such that their\r
2153          * combined length is a constant. So first we construct the\r
2154          * final form of this packet and defer its sending.\r
2155          */\r
2156         ssh2_pkt_defer(ssh, pkt);\r
2158         /*\r
2159          * Now construct an SSH_MSG_IGNORE which includes a string\r
2160          * that's an exact multiple of the cipher block size. (If\r
2161          * the cipher is NULL so that the block size is\r
2162          * unavailable, we don't do this trick at all, because we\r
2163          * gain nothing by it.)\r
2164          */\r
2165         if (ssh->cscipher &&\r
2166             !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2167             int stringlen, i;\r
2169             stringlen = (256 - ssh->deferred_len);\r
2170             stringlen += ssh->cscipher->blksize - 1;\r
2171             stringlen -= (stringlen % ssh->cscipher->blksize);\r
2172             if (ssh->cscomp) {\r
2173                 /*\r
2174                  * Temporarily disable actual compression, so we\r
2175                  * can guarantee to get this string exactly the\r
2176                  * length we want it. The compression-disabling\r
2177                  * routine should return an integer indicating how\r
2178                  * many bytes we should adjust our string length\r
2179                  * by.\r
2180                  */\r
2181                 stringlen -=\r
2182                     ssh->cscomp->disable_compression(ssh->cs_comp_ctx);\r
2183             }\r
2184             pkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2185             ssh2_pkt_addstring_start(pkt);\r
2186             for (i = 0; i < stringlen; i++) {\r
2187                 char c = (char) random_byte();\r
2188                 ssh2_pkt_addstring_data(pkt, &c, 1);\r
2189             }\r
2190             ssh2_pkt_defer(ssh, pkt);\r
2191         }\r
2192         ssh_pkt_defersend(ssh);\r
2193     }\r
2196 /*\r
2197  * Send all queued SSH-2 packets. We send them by means of\r
2198  * ssh2_pkt_defer_noqueue(), in case they included a pair of\r
2199  * packets that needed to be lumped together.\r
2200  */\r
2201 static void ssh2_pkt_queuesend(Ssh ssh)\r
2203     int i;\r
2205     assert(!ssh->queueing);\r
2207     for (i = 0; i < ssh->queuelen; i++)\r
2208         ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE);\r
2209     ssh->queuelen = 0;\r
2211     ssh_pkt_defersend(ssh);\r
2214 #if 0\r
2215 void bndebug(char *string, Bignum b)\r
2217     unsigned char *p;\r
2218     int i, len;\r
2219     p = ssh2_mpint_fmt(b, &len);\r
2220     debug(("%s", string));\r
2221     for (i = 0; i < len; i++)\r
2222         debug((" %02x", p[i]));\r
2223     debug(("\n"));\r
2224     sfree(p);\r
2226 #endif\r
2228 static void hash_mpint(const struct ssh_hash *h, void *s, Bignum b)\r
2230     unsigned char *p;\r
2231     int len;\r
2232     p = ssh2_mpint_fmt(b, &len);\r
2233     hash_string(h, s, p, len);\r
2234     sfree(p);\r
2237 /*\r
2238  * Packet decode functions for both SSH-1 and SSH-2.\r
2239  */\r
2240 static unsigned long ssh_pkt_getuint32(struct Packet *pkt)\r
2242     unsigned long value;\r
2243     if (pkt->length - pkt->savedpos < 4)\r
2244         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2245     value = GET_32BIT(pkt->body + pkt->savedpos);\r
2246     pkt->savedpos += 4;\r
2247     return value;\r
2249 static int ssh2_pkt_getbool(struct Packet *pkt)\r
2251     unsigned long value;\r
2252     if (pkt->length - pkt->savedpos < 1)\r
2253         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2254     value = pkt->body[pkt->savedpos] != 0;\r
2255     pkt->savedpos++;\r
2256     return value;\r
2258 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length)\r
2260     int len;\r
2261     *p = NULL;\r
2262     *length = 0;\r
2263     if (pkt->length - pkt->savedpos < 4)\r
2264         return;\r
2265     len = GET_32BIT(pkt->body + pkt->savedpos);\r
2266     if (len < 0)\r
2267         return;\r
2268     *length = len;\r
2269     pkt->savedpos += 4;\r
2270     if (pkt->length - pkt->savedpos < *length)\r
2271         return;\r
2272     *p = (char *)(pkt->body + pkt->savedpos);\r
2273     pkt->savedpos += *length;\r
2275 static void *ssh_pkt_getdata(struct Packet *pkt, int length)\r
2277     if (pkt->length - pkt->savedpos < length)\r
2278         return NULL;\r
2279     pkt->savedpos += length;\r
2280     return pkt->body + (pkt->savedpos - length);\r
2282 static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key,\r
2283                               unsigned char **keystr)\r
2285     int j;\r
2287     j = makekey(pkt->body + pkt->savedpos,\r
2288                 pkt->length - pkt->savedpos,\r
2289                 key, keystr, 0);\r
2291     if (j < 0)\r
2292         return FALSE;\r
2293     \r
2294     pkt->savedpos += j;\r
2295     assert(pkt->savedpos < pkt->length);\r
2297     return TRUE;\r
2299 static Bignum ssh1_pkt_getmp(struct Packet *pkt)\r
2301     int j;\r
2302     Bignum b;\r
2304     j = ssh1_read_bignum(pkt->body + pkt->savedpos,\r
2305                          pkt->length - pkt->savedpos, &b);\r
2307     if (j < 0)\r
2308         return NULL;\r
2310     pkt->savedpos += j;\r
2311     return b;\r
2313 static Bignum ssh2_pkt_getmp(struct Packet *pkt)\r
2315     char *p;\r
2316     int length;\r
2317     Bignum b;\r
2319     ssh_pkt_getstring(pkt, &p, &length);\r
2320     if (!p)\r
2321         return NULL;\r
2322     if (p[0] & 0x80)\r
2323         return NULL;\r
2324     b = bignum_from_bytes((unsigned char *)p, length);\r
2325     return b;\r
2328 /*\r
2329  * Helper function to add an SSH-2 signature blob to a packet.\r
2330  * Expects to be shown the public key blob as well as the signature\r
2331  * blob. Normally works just like ssh2_pkt_addstring, but will\r
2332  * fiddle with the signature packet if necessary for\r
2333  * BUG_SSH2_RSA_PADDING.\r
2334  */\r
2335 static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt,\r
2336                              void *pkblob_v, int pkblob_len,\r
2337                              void *sigblob_v, int sigblob_len)\r
2339     unsigned char *pkblob = (unsigned char *)pkblob_v;\r
2340     unsigned char *sigblob = (unsigned char *)sigblob_v;\r
2342     /* dmemdump(pkblob, pkblob_len); */\r
2343     /* dmemdump(sigblob, sigblob_len); */\r
2345     /*\r
2346      * See if this is in fact an ssh-rsa signature and a buggy\r
2347      * server; otherwise we can just do this the easy way.\r
2348      */\r
2349     if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) &&\r
2350         (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {\r
2351         int pos, len, siglen;\r
2353         /*\r
2354          * Find the byte length of the modulus.\r
2355          */\r
2357         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2358         pos += 4 + GET_32BIT(pkblob+pos);   /* skip over exponent */\r
2359         len = GET_32BIT(pkblob+pos);   /* find length of modulus */\r
2360         pos += 4;                      /* find modulus itself */\r
2361         while (len > 0 && pkblob[pos] == 0)\r
2362             len--, pos++;\r
2363         /* debug(("modulus length is %d\n", len)); */\r
2365         /*\r
2366          * Now find the signature integer.\r
2367          */\r
2368         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2369         siglen = GET_32BIT(sigblob+pos);\r
2370         /* debug(("signature length is %d\n", siglen)); */\r
2372         if (len != siglen) {\r
2373             unsigned char newlen[4];\r
2374             ssh2_pkt_addstring_start(pkt);\r
2375             ssh2_pkt_addstring_data(pkt, (char *)sigblob, pos);\r
2376             /* dmemdump(sigblob, pos); */\r
2377             pos += 4;                  /* point to start of actual sig */\r
2378             PUT_32BIT(newlen, len);\r
2379             ssh2_pkt_addstring_data(pkt, (char *)newlen, 4);\r
2380             /* dmemdump(newlen, 4); */\r
2381             newlen[0] = 0;\r
2382             while (len-- > siglen) {\r
2383                 ssh2_pkt_addstring_data(pkt, (char *)newlen, 1);\r
2384                 /* dmemdump(newlen, 1); */\r
2385             }\r
2386             ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen);\r
2387             /* dmemdump(sigblob+pos, siglen); */\r
2388             return;\r
2389         }\r
2391         /* Otherwise fall through and do it the easy way. */\r
2392     }\r
2394     ssh2_pkt_addstring_start(pkt);\r
2395     ssh2_pkt_addstring_data(pkt, (char *)sigblob, sigblob_len);\r
2398 /*\r
2399  * Examine the remote side's version string and compare it against\r
2400  * a list of known buggy implementations.\r
2401  */\r
2402 static void ssh_detect_bugs(Ssh ssh, char *vstring)\r
2404     char *imp;                         /* pointer to implementation part */\r
2405     imp = vstring;\r
2406     imp += strcspn(imp, "-");\r
2407     if (*imp) imp++;\r
2408     imp += strcspn(imp, "-");\r
2409     if (*imp) imp++;\r
2411     ssh->remote_bugs = 0;\r
2413     /*\r
2414      * General notes on server version strings:\r
2415      *  - Not all servers reporting "Cisco-1.25" have all the bugs listed\r
2416      *    here -- in particular, we've heard of one that's perfectly happy\r
2417      *    with SSH1_MSG_IGNOREs -- but this string never seems to change,\r
2418      *    so we can't distinguish them.\r
2419      */\r
2420     if (ssh->cfg.sshbug_ignore1 == FORCE_ON ||\r
2421         (ssh->cfg.sshbug_ignore1 == AUTO &&\r
2422          (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||\r
2423           !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||\r
2424           !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||\r
2425           !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {\r
2426         /*\r
2427          * These versions don't support SSH1_MSG_IGNORE, so we have\r
2428          * to use a different defence against password length\r
2429          * sniffing.\r
2430          */\r
2431         ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;\r
2432         logevent("We believe remote version has SSH-1 ignore bug");\r
2433     }\r
2435     if (ssh->cfg.sshbug_plainpw1 == FORCE_ON ||\r
2436         (ssh->cfg.sshbug_plainpw1 == AUTO &&\r
2437          (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) {\r
2438         /*\r
2439          * These versions need a plain password sent; they can't\r
2440          * handle having a null and a random length of data after\r
2441          * the password.\r
2442          */\r
2443         ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;\r
2444         logevent("We believe remote version needs a plain SSH-1 password");\r
2445     }\r
2447     if (ssh->cfg.sshbug_rsa1 == FORCE_ON ||\r
2448         (ssh->cfg.sshbug_rsa1 == AUTO &&\r
2449          (!strcmp(imp, "Cisco-1.25")))) {\r
2450         /*\r
2451          * These versions apparently have no clue whatever about\r
2452          * RSA authentication and will panic and die if they see\r
2453          * an AUTH_RSA message.\r
2454          */\r
2455         ssh->remote_bugs |= BUG_CHOKES_ON_RSA;\r
2456         logevent("We believe remote version can't handle SSH-1 RSA authentication");\r
2457     }\r
2459     if (ssh->cfg.sshbug_hmac2 == FORCE_ON ||\r
2460         (ssh->cfg.sshbug_hmac2 == AUTO &&\r
2461          !wc_match("* VShell", imp) &&\r
2462          (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) ||\r
2463           wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) ||\r
2464           wc_match("2.1 *", imp)))) {\r
2465         /*\r
2466          * These versions have the HMAC bug.\r
2467          */\r
2468         ssh->remote_bugs |= BUG_SSH2_HMAC;\r
2469         logevent("We believe remote version has SSH-2 HMAC bug");\r
2470     }\r
2472     if (ssh->cfg.sshbug_derivekey2 == FORCE_ON ||\r
2473         (ssh->cfg.sshbug_derivekey2 == AUTO &&\r
2474          !wc_match("* VShell", imp) &&\r
2475          (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) {\r
2476         /*\r
2477          * These versions have the key-derivation bug (failing to\r
2478          * include the literal shared secret in the hashes that\r
2479          * generate the keys).\r
2480          */\r
2481         ssh->remote_bugs |= BUG_SSH2_DERIVEKEY;\r
2482         logevent("We believe remote version has SSH-2 key-derivation bug");\r
2483     }\r
2485     if (ssh->cfg.sshbug_rsapad2 == FORCE_ON ||\r
2486         (ssh->cfg.sshbug_rsapad2 == AUTO &&\r
2487          (wc_match("OpenSSH_2.[5-9]*", imp) ||\r
2488           wc_match("OpenSSH_3.[0-2]*", imp)))) {\r
2489         /*\r
2490          * These versions have the SSH-2 RSA padding bug.\r
2491          */\r
2492         ssh->remote_bugs |= BUG_SSH2_RSA_PADDING;\r
2493         logevent("We believe remote version has SSH-2 RSA padding bug");\r
2494     }\r
2496     if (ssh->cfg.sshbug_pksessid2 == FORCE_ON ||\r
2497         (ssh->cfg.sshbug_pksessid2 == AUTO &&\r
2498          wc_match("OpenSSH_2.[0-2]*", imp))) {\r
2499         /*\r
2500          * These versions have the SSH-2 session-ID bug in\r
2501          * public-key authentication.\r
2502          */\r
2503         ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID;\r
2504         logevent("We believe remote version has SSH-2 public-key-session-ID bug");\r
2505     }\r
2507     if (ssh->cfg.sshbug_rekey2 == FORCE_ON ||\r
2508         (ssh->cfg.sshbug_rekey2 == AUTO &&\r
2509          (wc_match("DigiSSH_2.0", imp) ||\r
2510           wc_match("OpenSSH_2.[0-4]*", imp) ||\r
2511           wc_match("OpenSSH_2.5.[0-3]*", imp) ||\r
2512           wc_match("Sun_SSH_1.0", imp) ||\r
2513           wc_match("Sun_SSH_1.0.1", imp) ||\r
2514           /* All versions <= 1.2.6 (they changed their format in 1.2.7) */\r
2515           wc_match("WeOnlyDo-*", imp)))) {\r
2516         /*\r
2517          * These versions have the SSH-2 rekey bug.\r
2518          */\r
2519         ssh->remote_bugs |= BUG_SSH2_REKEY;\r
2520         logevent("We believe remote version has SSH-2 rekey bug");\r
2521     }\r
2523     if (ssh->cfg.sshbug_maxpkt2 == FORCE_ON ||\r
2524         (ssh->cfg.sshbug_maxpkt2 == AUTO &&\r
2525          (wc_match("1.36_sshlib GlobalSCAPE", imp) ||\r
2526           wc_match("1.36 sshlib: GlobalScape", imp)))) {\r
2527         /*\r
2528          * This version ignores our makpkt and needs to be throttled.\r
2529          */\r
2530         ssh->remote_bugs |= BUG_SSH2_MAXPKT;\r
2531         logevent("We believe remote version ignores SSH-2 maximum packet size");\r
2532     }\r
2534     if (ssh->cfg.sshbug_ignore2 == FORCE_ON) {\r
2535         /*\r
2536          * Servers that don't support SSH2_MSG_IGNORE. Currently,\r
2537          * none detected automatically.\r
2538          */\r
2539         ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;\r
2540         logevent("We believe remote version has SSH-2 ignore bug");\r
2541     }\r
2544 /*\r
2545  * The `software version' part of an SSH version string is required\r
2546  * to contain no spaces or minus signs.\r
2547  */\r
2548 static void ssh_fix_verstring(char *str)\r
2550     /* Eat "SSH-<protoversion>-". */\r
2551     assert(*str == 'S'); str++;\r
2552     assert(*str == 'S'); str++;\r
2553     assert(*str == 'H'); str++;\r
2554     assert(*str == '-'); str++;\r
2555     while (*str && *str != '-') str++;\r
2556     assert(*str == '-'); str++;\r
2558     /* Convert minus signs and spaces in the remaining string into\r
2559      * underscores. */\r
2560     while (*str) {\r
2561         if (*str == '-' || *str == ' ')\r
2562             *str = '_';\r
2563         str++;\r
2564     }\r
2567 /*\r
2568  * Send an appropriate SSH version string.\r
2569  */\r
2570 static void ssh_send_verstring(Ssh ssh, char *svers)\r
2572     char *verstring;\r
2574     if (ssh->version == 2) {\r
2575         /*\r
2576          * Construct a v2 version string.\r
2577          */\r
2578         verstring = dupprintf("SSH-2.0-%s\015\012", sshver);\r
2579     } else {\r
2580         /*\r
2581          * Construct a v1 version string.\r
2582          */\r
2583         verstring = dupprintf("SSH-%s-%s\012",\r
2584                               (ssh_versioncmp(svers, "1.5") <= 0 ?\r
2585                                svers : "1.5"),\r
2586                               sshver);\r
2587     }\r
2589     ssh_fix_verstring(verstring);\r
2591     if (ssh->version == 2) {\r
2592         size_t len;\r
2593         /*\r
2594          * Record our version string.\r
2595          */\r
2596         len = strcspn(verstring, "\015\012");\r
2597         ssh->v_c = snewn(len + 1, char);\r
2598         memcpy(ssh->v_c, verstring, len);\r
2599         ssh->v_c[len] = 0;\r
2600     }\r
2602     logeventf(ssh, "We claim version: %.*s",\r
2603               strcspn(verstring, "\015\012"), verstring);\r
2604     s_write(ssh, verstring, strlen(verstring));\r
2605     sfree(verstring);\r
2608 static int do_ssh_init(Ssh ssh, unsigned char c)\r
2610     struct do_ssh_init_state {\r
2611         int vslen;\r
2612         char version[10];\r
2613         char *vstring;\r
2614         int vstrsize;\r
2615         int i;\r
2616         int proto1, proto2;\r
2617     };\r
2618     crState(do_ssh_init_state);\r
2620     crBegin(ssh->do_ssh_init_crstate);\r
2622     /* Search for a line beginning with the string "SSH-" in the input. */\r
2623     for (;;) {\r
2624         if (c != 'S') goto no;\r
2625         crReturn(1);\r
2626         if (c != 'S') goto no;\r
2627         crReturn(1);\r
2628         if (c != 'H') goto no;\r
2629         crReturn(1);\r
2630         if (c != '-') goto no;\r
2631         break;\r
2632       no:\r
2633         while (c != '\012')\r
2634             crReturn(1);\r
2635         crReturn(1);\r
2636     }\r
2638     s->vstrsize = 16;\r
2639     s->vstring = snewn(s->vstrsize, char);\r
2640     strcpy(s->vstring, "SSH-");\r
2641     s->vslen = 4;\r
2642     s->i = 0;\r
2643     while (1) {\r
2644         crReturn(1);                   /* get another char */\r
2645         if (s->vslen >= s->vstrsize - 1) {\r
2646             s->vstrsize += 16;\r
2647             s->vstring = sresize(s->vstring, s->vstrsize, char);\r
2648         }\r
2649         s->vstring[s->vslen++] = c;\r
2650         if (s->i >= 0) {\r
2651             if (c == '-') {\r
2652                 s->version[s->i] = '\0';\r
2653                 s->i = -1;\r
2654             } else if (s->i < sizeof(s->version) - 1)\r
2655                 s->version[s->i++] = c;\r
2656         } else if (c == '\012')\r
2657             break;\r
2658     }\r
2660     ssh->agentfwd_enabled = FALSE;\r
2661     ssh->rdpkt2_state.incoming_sequence = 0;\r
2663     s->vstring[s->vslen] = 0;\r
2664     s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */\r
2665     logeventf(ssh, "Server version: %s", s->vstring);\r
2666     ssh_detect_bugs(ssh, s->vstring);\r
2668     /*\r
2669      * Decide which SSH protocol version to support.\r
2670      */\r
2672     /* Anything strictly below "2.0" means protocol 1 is supported. */\r
2673     s->proto1 = ssh_versioncmp(s->version, "2.0") < 0;\r
2674     /* Anything greater or equal to "1.99" means protocol 2 is supported. */\r
2675     s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;\r
2677     if (ssh->cfg.sshprot == 0 && !s->proto1) {\r
2678         bombout(("SSH protocol version 1 required by user but not provided by server"));\r
2679         crStop(0);\r
2680     }\r
2681     if (ssh->cfg.sshprot == 3 && !s->proto2) {\r
2682         bombout(("SSH protocol version 2 required by user but not provided by server"));\r
2683         crStop(0);\r
2684     }\r
2686     if (s->proto2 && (ssh->cfg.sshprot >= 2 || !s->proto1))\r
2687         ssh->version = 2;\r
2688     else\r
2689         ssh->version = 1;\r
2691     logeventf(ssh, "Using SSH protocol version %d", ssh->version);\r
2693     /* Send the version string, if we haven't already */\r
2694     if (ssh->cfg.sshprot != 3)\r
2695         ssh_send_verstring(ssh, s->version);\r
2697     if (ssh->version == 2) {\r
2698         size_t len;\r
2699         /*\r
2700          * Record their version string.\r
2701          */\r
2702         len = strcspn(s->vstring, "\015\012");\r
2703         ssh->v_s = snewn(len + 1, char);\r
2704         memcpy(ssh->v_s, s->vstring, len);\r
2705         ssh->v_s[len] = 0;\r
2706             \r
2707         /*\r
2708          * Initialise SSH-2 protocol.\r
2709          */\r
2710         ssh->protocol = ssh2_protocol;\r
2711         ssh2_protocol_setup(ssh);\r
2712         ssh->s_rdpkt = ssh2_rdpkt;\r
2713     } else {\r
2714         /*\r
2715          * Initialise SSH-1 protocol.\r
2716          */\r
2717         ssh->protocol = ssh1_protocol;\r
2718         ssh1_protocol_setup(ssh);\r
2719         ssh->s_rdpkt = ssh1_rdpkt;\r
2720     }\r
2721     if (ssh->version == 2)\r
2722         do_ssh2_transport(ssh, NULL, -1, NULL);\r
2724     update_specials_menu(ssh->frontend);\r
2725     ssh->state = SSH_STATE_BEFORE_SIZE;\r
2726     ssh->pinger = pinger_new(&ssh->cfg, &ssh_backend, ssh);\r
2728     sfree(s->vstring);\r
2730     crFinish(0);\r
2733 static void ssh_process_incoming_data(Ssh ssh,\r
2734                                       unsigned char **data, int *datalen)\r
2736     struct Packet *pktin;\r
2738     pktin = ssh->s_rdpkt(ssh, data, datalen);\r
2739     if (pktin) {\r
2740         ssh->protocol(ssh, NULL, 0, pktin);\r
2741         ssh_free_packet(pktin);\r
2742     }\r
2745 static void ssh_queue_incoming_data(Ssh ssh,\r
2746                                     unsigned char **data, int *datalen)\r
2748     bufchain_add(&ssh->queued_incoming_data, *data, *datalen);\r
2749     *data += *datalen;\r
2750     *datalen = 0;\r
2753 static void ssh_process_queued_incoming_data(Ssh ssh)\r
2755     void *vdata;\r
2756     unsigned char *data;\r
2757     int len, origlen;\r
2759     while (!ssh->frozen && bufchain_size(&ssh->queued_incoming_data)) {\r
2760         bufchain_prefix(&ssh->queued_incoming_data, &vdata, &len);\r
2761         data = vdata;\r
2762         origlen = len;\r
2764         while (!ssh->frozen && len > 0)\r
2765             ssh_process_incoming_data(ssh, &data, &len);\r
2767         if (origlen > len)\r
2768             bufchain_consume(&ssh->queued_incoming_data, origlen - len);\r
2769     }\r
2772 static void ssh_set_frozen(Ssh ssh, int frozen)\r
2774     if (ssh->s)\r
2775         sk_set_frozen(ssh->s, frozen);\r
2776     ssh->frozen = frozen;\r
2779 static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)\r
2781     /* Log raw data, if we're in that mode. */\r
2782     if (ssh->logctx)\r
2783         log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,\r
2784                    0, NULL, NULL);\r
2786     crBegin(ssh->ssh_gotdata_crstate);\r
2788     /*\r
2789      * To begin with, feed the characters one by one to the\r
2790      * protocol initialisation / selection function do_ssh_init().\r
2791      * When that returns 0, we're done with the initial greeting\r
2792      * exchange and can move on to packet discipline.\r
2793      */\r
2794     while (1) {\r
2795         int ret;                       /* need not be kept across crReturn */\r
2796         if (datalen == 0)\r
2797             crReturnV;                 /* more data please */\r
2798         ret = do_ssh_init(ssh, *data);\r
2799         data++;\r
2800         datalen--;\r
2801         if (ret == 0)\r
2802             break;\r
2803     }\r
2805     /*\r
2806      * We emerge from that loop when the initial negotiation is\r
2807      * over and we have selected an s_rdpkt function. Now pass\r
2808      * everything to s_rdpkt, and then pass the resulting packets\r
2809      * to the proper protocol handler.\r
2810      */\r
2812     while (1) {\r
2813         while (bufchain_size(&ssh->queued_incoming_data) > 0 || datalen > 0) {\r
2814             if (ssh->frozen) {\r
2815                 ssh_queue_incoming_data(ssh, &data, &datalen);\r
2816                 /* This uses up all data and cannot cause anything interesting\r
2817                  * to happen; indeed, for anything to happen at all, we must\r
2818                  * return, so break out. */\r
2819                 break;\r
2820             } else if (bufchain_size(&ssh->queued_incoming_data) > 0) {\r
2821                 /* This uses up some or all data, and may freeze the\r
2822                  * session. */\r
2823                 ssh_process_queued_incoming_data(ssh);\r
2824             } else {\r
2825                 /* This uses up some or all data, and may freeze the\r
2826                  * session. */\r
2827                 ssh_process_incoming_data(ssh, &data, &datalen);\r
2828             }\r
2829             /* FIXME this is probably EBW. */\r
2830             if (ssh->state == SSH_STATE_CLOSED)\r
2831                 return;\r
2832         }\r
2833         /* We're out of data. Go and get some more. */\r
2834         crReturnV;\r
2835     }\r
2836     crFinishV;\r
2839 static int ssh_do_close(Ssh ssh, int notify_exit)\r
2841     int ret = 0;\r
2842     struct ssh_channel *c;\r
2844     ssh->state = SSH_STATE_CLOSED;\r
2845     expire_timer_context(ssh);\r
2846     if (ssh->s) {\r
2847         sk_close(ssh->s);\r
2848         ssh->s = NULL;\r
2849         if (notify_exit)\r
2850             notify_remote_exit(ssh->frontend);\r
2851         else\r
2852             ret = 1;\r
2853     }\r
2854     /*\r
2855      * Now we must shut down any port- and X-forwarded channels going\r
2856      * through this connection.\r
2857      */\r
2858     if (ssh->channels) {\r
2859         while (NULL != (c = index234(ssh->channels, 0))) {\r
2860             switch (c->type) {\r
2861               case CHAN_X11:\r
2862                 x11_close(c->u.x11.s);\r
2863                 break;\r
2864               case CHAN_SOCKDATA:\r
2865               case CHAN_SOCKDATA_DORMANT:\r
2866                 pfd_close(c->u.pfd.s);\r
2867                 break;\r
2868             }\r
2869             del234(ssh->channels, c); /* moving next one to index 0 */\r
2870             if (ssh->version == 2)\r
2871                 bufchain_clear(&c->v.v2.outbuffer);\r
2872             sfree(c);\r
2873         }\r
2874     }\r
2875     /*\r
2876      * Go through port-forwardings, and close any associated\r
2877      * listening sockets.\r
2878      */\r
2879     if (ssh->portfwds) {\r
2880         struct ssh_portfwd *pf;\r
2881         while (NULL != (pf = index234(ssh->portfwds, 0))) {\r
2882             /* Dispose of any listening socket. */\r
2883             if (pf->local)\r
2884                 pfd_terminate(pf->local);\r
2885             del234(ssh->portfwds, pf); /* moving next one to index 0 */\r
2886             free_portfwd(pf);\r
2887         }\r
2888         freetree234(ssh->portfwds);\r
2889         ssh->portfwds = NULL;\r
2890     }\r
2892     return ret;\r
2895 static void ssh_log(Plug plug, int type, SockAddr addr, int port,\r
2896                     const char *error_msg, int error_code)\r
2898     Ssh ssh = (Ssh) plug;\r
2899     char addrbuf[256], *msg;\r
2901     sk_getaddr(addr, addrbuf, lenof(addrbuf));\r
2903     if (type == 0)\r
2904         msg = dupprintf("Connecting to %s port %d", addrbuf, port);\r
2905     else\r
2906         msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);\r
2908     logevent(msg);\r
2909     sfree(msg);\r
2912 static int ssh_closing(Plug plug, const char *error_msg, int error_code,\r
2913                        int calling_back)\r
2915     Ssh ssh = (Ssh) plug;\r
2916     int need_notify = ssh_do_close(ssh, FALSE);\r
2918     if (!error_msg) {\r
2919         if (!ssh->close_expected)\r
2920             error_msg = "Server unexpectedly closed network connection";\r
2921         else\r
2922             error_msg = "Server closed network connection";\r
2923     }\r
2925     if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0)\r
2926         ssh->exitcode = 0;\r
2928     if (need_notify)\r
2929         notify_remote_exit(ssh->frontend);\r
2931     if (error_msg)\r
2932         logevent(error_msg);\r
2933     if (!ssh->close_expected || !ssh->clean_exit)\r
2934         connection_fatal(ssh->frontend, "%s", error_msg);\r
2935     return 0;\r
2938 static int ssh_receive(Plug plug, int urgent, char *data, int len)\r
2940     Ssh ssh = (Ssh) plug;\r
2941     ssh_gotdata(ssh, (unsigned char *)data, len);\r
2942     if (ssh->state == SSH_STATE_CLOSED) {\r
2943         ssh_do_close(ssh, TRUE);\r
2944         return 0;\r
2945     }\r
2946     return 1;\r
2949 static void ssh_sent(Plug plug, int bufsize)\r
2951     Ssh ssh = (Ssh) plug;\r
2952     /*\r
2953      * If the send backlog on the SSH socket itself clears, we\r
2954      * should unthrottle the whole world if it was throttled.\r
2955      */\r
2956     if (bufsize < SSH_MAX_BACKLOG)\r
2957         ssh_throttle_all(ssh, 0, bufsize);\r
2960 /*\r
2961  * Connect to specified host and port.\r
2962  * Returns an error message, or NULL on success.\r
2963  * Also places the canonical host name into `realhost'. It must be\r
2964  * freed by the caller.\r
2965  */\r
2966 static const char *connect_to_host(Ssh ssh, char *host, int port,\r
2967                                    char **realhost, int nodelay, int keepalive)\r
2969     static const struct plug_function_table fn_table = {\r
2970         ssh_log,\r
2971         ssh_closing,\r
2972         ssh_receive,\r
2973         ssh_sent,\r
2974         NULL\r
2975     };\r
2977     SockAddr addr;\r
2978     const char *err;\r
2980     if (*ssh->cfg.loghost) {\r
2981         char *colon;\r
2983         ssh->savedhost = dupstr(ssh->cfg.loghost);\r
2984         ssh->savedport = 22;           /* default ssh port */\r
2986         /*\r
2987          * A colon suffix on savedhost also lets us affect\r
2988          * savedport.\r
2989          * \r
2990          * (FIXME: do something about IPv6 address literals here.)\r
2991          */\r
2992         colon = strrchr(ssh->savedhost, ':');\r
2993         if (colon) {\r
2994             *colon++ = '\0';\r
2995             if (*colon)\r
2996                 ssh->savedport = atoi(colon);\r
2997         }\r
2998     } else {\r
2999         ssh->savedhost = dupstr(host);\r
3000         if (port < 0)\r
3001             port = 22;                 /* default ssh port */\r
3002         ssh->savedport = port;\r
3003     }\r
3005     /*\r
3006      * Try to find host.\r
3007      */\r
3008     logeventf(ssh, "Looking up host \"%s\"%s", host,\r
3009               (ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :\r
3010                (ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : "")));\r
3011     addr = name_lookup(host, port, realhost, &ssh->cfg,\r
3012                        ssh->cfg.addressfamily);\r
3013     if ((err = sk_addr_error(addr)) != NULL) {\r
3014         sk_addr_free(addr);\r
3015         return err;\r
3016     }\r
3017     ssh->fullhostname = dupstr(*realhost);   /* save in case of GSSAPI */\r
3019     /*\r
3020      * Open socket.\r
3021      */\r
3022     ssh->fn = &fn_table;\r
3023     ssh->s = new_connection(addr, *realhost, port,\r
3024                             0, 1, nodelay, keepalive, (Plug) ssh, &ssh->cfg);\r
3025     if ((err = sk_socket_error(ssh->s)) != NULL) {\r
3026         ssh->s = NULL;\r
3027         notify_remote_exit(ssh->frontend);\r
3028         return err;\r
3029     }\r
3031     /*\r
3032      * If the SSH version number's fixed, set it now, and if it's SSH-2,\r
3033      * send the version string too.\r
3034      */\r
3035     if (ssh->cfg.sshprot == 0)\r
3036         ssh->version = 1;\r
3037     if (ssh->cfg.sshprot == 3) {\r
3038         ssh->version = 2;\r
3039         ssh_send_verstring(ssh, NULL);\r
3040     }\r
3042     /*\r
3043      * loghost, if configured, overrides realhost.\r
3044      */\r
3045     if (*ssh->cfg.loghost) {\r
3046         sfree(*realhost);\r
3047         *realhost = dupstr(ssh->cfg.loghost);\r
3048     }\r
3050     return NULL;\r
3053 /*\r
3054  * Throttle or unthrottle the SSH connection.\r
3055  */\r
3056 static void ssh_throttle_conn(Ssh ssh, int adjust)\r
3058     int old_count = ssh->conn_throttle_count;\r
3059     ssh->conn_throttle_count += adjust;\r
3060     assert(ssh->conn_throttle_count >= 0);\r
3061     if (ssh->conn_throttle_count && !old_count) {\r
3062         ssh_set_frozen(ssh, 1);\r
3063     } else if (!ssh->conn_throttle_count && old_count) {\r
3064         ssh_set_frozen(ssh, 0);\r
3065     }\r
3068 /*\r
3069  * Throttle or unthrottle _all_ local data streams (for when sends\r
3070  * on the SSH connection itself back up).\r
3071  */\r
3072 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize)\r
3074     int i;\r
3075     struct ssh_channel *c;\r
3077     if (enable == ssh->throttled_all)\r
3078         return;\r
3079     ssh->throttled_all = enable;\r
3080     ssh->overall_bufsize = bufsize;\r
3081     if (!ssh->channels)\r
3082         return;\r
3083     for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) {\r
3084         switch (c->type) {\r
3085           case CHAN_MAINSESSION:\r
3086             /*\r
3087              * This is treated separately, outside the switch.\r
3088              */\r
3089             break;\r
3090           case CHAN_X11:\r
3091             x11_override_throttle(c->u.x11.s, enable);\r
3092             break;\r
3093           case CHAN_AGENT:\r
3094             /* Agent channels require no buffer management. */\r
3095             break;\r
3096           case CHAN_SOCKDATA:\r
3097             pfd_override_throttle(c->u.pfd.s, enable);\r
3098             break;\r
3099         }\r
3100     }\r
3103 static void ssh_agent_callback(void *sshv, void *reply, int replylen)\r
3105     Ssh ssh = (Ssh) sshv;\r
3107     ssh->agent_response = reply;\r
3108     ssh->agent_response_len = replylen;\r
3110     if (ssh->version == 1)\r
3111         do_ssh1_login(ssh, NULL, -1, NULL);\r
3112     else\r
3113         do_ssh2_authconn(ssh, NULL, -1, NULL);\r
3116 static void ssh_dialog_callback(void *sshv, int ret)\r
3118     Ssh ssh = (Ssh) sshv;\r
3120     ssh->user_response = ret;\r
3122     if (ssh->version == 1)\r
3123         do_ssh1_login(ssh, NULL, -1, NULL);\r
3124     else\r
3125         do_ssh2_transport(ssh, NULL, -1, NULL);\r
3127     /*\r
3128      * This may have unfrozen the SSH connection, so do a\r
3129      * queued-data run.\r
3130      */\r
3131     ssh_process_queued_incoming_data(ssh);\r
3134 static void ssh_agentf_callback(void *cv, void *reply, int replylen)\r
3136     struct ssh_channel *c = (struct ssh_channel *)cv;\r
3137     Ssh ssh = c->ssh;\r
3138     void *sentreply = reply;\r
3140     if (!sentreply) {\r
3141         /* Fake SSH_AGENT_FAILURE. */\r
3142         sentreply = "\0\0\0\1\5";\r
3143         replylen = 5;\r
3144     }\r
3145     if (ssh->version == 2) {\r
3146         ssh2_add_channel_data(c, sentreply, replylen);\r
3147         ssh2_try_send(c);\r
3148     } else {\r
3149         send_packet(ssh, SSH1_MSG_CHANNEL_DATA,\r
3150                     PKT_INT, c->remoteid,\r
3151                     PKT_INT, replylen,\r
3152                     PKTT_DATA,\r
3153                     PKT_DATA, sentreply, replylen,\r
3154                     PKTT_OTHER,\r
3155                     PKT_END);\r
3156     }\r
3157     if (reply)\r
3158         sfree(reply);\r
3161 /*\r
3162  * Client-initiated disconnection. Send a DISCONNECT if `wire_reason'\r
3163  * non-NULL, otherwise just close the connection. `client_reason' == NULL\r
3164  * => log `wire_reason'.\r
3165  */\r
3166 static void ssh_disconnect(Ssh ssh, char *client_reason, char *wire_reason,\r
3167                            int code, int clean_exit)\r
3169     char *error;\r
3170     if (!client_reason)\r
3171         client_reason = wire_reason;\r
3172     if (client_reason)\r
3173         error = dupprintf("Disconnected: %s", client_reason);\r
3174     else\r
3175         error = dupstr("Disconnected");\r
3176     if (wire_reason) {\r
3177         if (ssh->version == 1) {\r
3178             send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason,\r
3179                         PKT_END);\r
3180         } else if (ssh->version == 2) {\r
3181             struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT);\r
3182             ssh2_pkt_adduint32(pktout, code);\r
3183             ssh2_pkt_addstring(pktout, wire_reason);\r
3184             ssh2_pkt_addstring(pktout, "en");   /* language tag */\r
3185             ssh2_pkt_send_noqueue(ssh, pktout);\r
3186         }\r
3187     }\r
3188     ssh->close_expected = TRUE;\r
3189     ssh->clean_exit = clean_exit;\r
3190     ssh_closing((Plug)ssh, error, 0, 0);\r
3191     sfree(error);\r
3194 /*\r
3195  * Handle the key exchange and user authentication phases.\r
3196  */\r
3197 static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,\r
3198                          struct Packet *pktin)\r
3200     int i, j, ret;\r
3201     unsigned char cookie[8], *ptr;\r
3202     struct RSAKey servkey, hostkey;\r
3203     struct MD5Context md5c;\r
3204     struct do_ssh1_login_state {\r
3205         int len;\r
3206         unsigned char *rsabuf, *keystr1, *keystr2;\r
3207         unsigned long supported_ciphers_mask, supported_auths_mask;\r
3208         int tried_publickey, tried_agent;\r
3209         int tis_auth_refused, ccard_auth_refused;\r
3210         unsigned char session_id[16];\r
3211         int cipher_type;\r
3212         char username[100];\r
3213         void *publickey_blob;\r
3214         int publickey_bloblen;\r
3215         char *publickey_comment;\r
3216         int publickey_encrypted;\r
3217         prompts_t *cur_prompt;\r
3218         char c;\r
3219         int pwpkt_type;\r
3220         unsigned char request[5], *response, *p;\r
3221         int responselen;\r
3222         int keyi, nkeys;\r
3223         int authed;\r
3224         struct RSAKey key;\r
3225         Bignum challenge;\r
3226         char *commentp;\r
3227         int commentlen;\r
3228         int dlgret;\r
3229     };\r
3230     crState(do_ssh1_login_state);\r
3232     crBegin(ssh->do_ssh1_login_crstate);\r
3234     if (!pktin)\r
3235         crWaitUntil(pktin);\r
3237     if (pktin->type != SSH1_SMSG_PUBLIC_KEY) {\r
3238         bombout(("Public key packet not received"));\r
3239         crStop(0);\r
3240     }\r
3242     logevent("Received public keys");\r
3244     ptr = ssh_pkt_getdata(pktin, 8);\r
3245     if (!ptr) {\r
3246         bombout(("SSH-1 public key packet stopped before random cookie"));\r
3247         crStop(0);\r
3248     }\r
3249     memcpy(cookie, ptr, 8);\r
3251     if (!ssh1_pkt_getrsakey(pktin, &servkey, &s->keystr1) ||\r
3252         !ssh1_pkt_getrsakey(pktin, &hostkey, &s->keystr2)) {    \r
3253         bombout(("Failed to read SSH-1 public keys from public key packet"));\r
3254         crStop(0);\r
3255     }\r
3257     /*\r
3258      * Log the host key fingerprint.\r
3259      */\r
3260     {\r
3261         char logmsg[80];\r
3262         logevent("Host key fingerprint is:");\r
3263         strcpy(logmsg, "      ");\r
3264         hostkey.comment = NULL;\r
3265         rsa_fingerprint(logmsg + strlen(logmsg),\r
3266                         sizeof(logmsg) - strlen(logmsg), &hostkey);\r
3267         logevent(logmsg);\r
3268     }\r
3270     ssh->v1_remote_protoflags = ssh_pkt_getuint32(pktin);\r
3271     s->supported_ciphers_mask = ssh_pkt_getuint32(pktin);\r
3272     s->supported_auths_mask = ssh_pkt_getuint32(pktin);\r
3273     if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA))\r
3274         s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA);\r
3276     ssh->v1_local_protoflags =\r
3277         ssh->v1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED;\r
3278     ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;\r
3280     MD5Init(&md5c);\r
3281     MD5Update(&md5c, s->keystr2, hostkey.bytes);\r
3282     MD5Update(&md5c, s->keystr1, servkey.bytes);\r
3283     MD5Update(&md5c, cookie, 8);\r
3284     MD5Final(s->session_id, &md5c);\r
3286     for (i = 0; i < 32; i++)\r
3287         ssh->session_key[i] = random_byte();\r
3289     /*\r
3290      * Verify that the `bits' and `bytes' parameters match.\r
3291      */\r
3292     if (hostkey.bits > hostkey.bytes * 8 ||\r
3293         servkey.bits > servkey.bytes * 8) {\r
3294         bombout(("SSH-1 public keys were badly formatted"));\r
3295         crStop(0);\r
3296     }\r
3298     s->len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);\r
3300     s->rsabuf = snewn(s->len, unsigned char);\r
3302     /*\r
3303      * Verify the host key.\r
3304      */\r
3305     {\r
3306         /*\r
3307          * First format the key into a string.\r
3308          */\r
3309         int len = rsastr_len(&hostkey);\r
3310         char fingerprint[100];\r
3311         char *keystr = snewn(len, char);\r
3312         rsastr_fmt(keystr, &hostkey);\r
3313         rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);\r
3315         ssh_set_frozen(ssh, 1);\r
3316         s->dlgret = verify_ssh_host_key(ssh->frontend,\r
3317                                         ssh->savedhost, ssh->savedport,\r
3318                                         "rsa", keystr, fingerprint,\r
3319                                         ssh_dialog_callback, ssh);\r
3320         sfree(keystr);\r
3321         if (s->dlgret < 0) {\r
3322             do {\r
3323                 crReturn(0);\r
3324                 if (pktin) {\r
3325                     bombout(("Unexpected data from server while waiting"\r
3326                              " for user host key response"));\r
3327                     crStop(0);\r
3328                 }\r
3329             } while (pktin || inlen > 0);\r
3330             s->dlgret = ssh->user_response;\r
3331         }\r
3332         ssh_set_frozen(ssh, 0);\r
3334         if (s->dlgret == 0) {\r
3335             ssh_disconnect(ssh, "User aborted at host key verification",\r
3336                            NULL, 0, TRUE);\r
3337             crStop(0);\r
3338         }\r
3339     }\r
3341     for (i = 0; i < 32; i++) {\r
3342         s->rsabuf[i] = ssh->session_key[i];\r
3343         if (i < 16)\r
3344             s->rsabuf[i] ^= s->session_id[i];\r
3345     }\r
3347     if (hostkey.bytes > servkey.bytes) {\r
3348         ret = rsaencrypt(s->rsabuf, 32, &servkey);\r
3349         if (ret)\r
3350             ret = rsaencrypt(s->rsabuf, servkey.bytes, &hostkey);\r
3351     } else {\r
3352         ret = rsaencrypt(s->rsabuf, 32, &hostkey);\r
3353         if (ret)\r
3354             ret = rsaencrypt(s->rsabuf, hostkey.bytes, &servkey);\r
3355     }\r
3356     if (!ret) {\r
3357         bombout(("SSH-1 public key encryptions failed due to bad formatting"));\r
3358         crStop(0);      \r
3359     }\r
3361     logevent("Encrypted session key");\r
3363     {\r
3364         int cipher_chosen = 0, warn = 0;\r
3365         char *cipher_string = NULL;\r
3366         int i;\r
3367         for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) {\r
3368             int next_cipher = ssh->cfg.ssh_cipherlist[i];\r
3369             if (next_cipher == CIPHER_WARN) {\r
3370                 /* If/when we choose a cipher, warn about it */\r
3371                 warn = 1;\r
3372             } else if (next_cipher == CIPHER_AES) {\r
3373                 /* XXX Probably don't need to mention this. */\r
3374                 logevent("AES not supported in SSH-1, skipping");\r
3375             } else {\r
3376                 switch (next_cipher) {\r
3377                   case CIPHER_3DES:     s->cipher_type = SSH_CIPHER_3DES;\r
3378                                         cipher_string = "3DES"; break;\r
3379                   case CIPHER_BLOWFISH: s->cipher_type = SSH_CIPHER_BLOWFISH;\r
3380                                         cipher_string = "Blowfish"; break;\r
3381                   case CIPHER_DES:      s->cipher_type = SSH_CIPHER_DES;\r
3382                                         cipher_string = "single-DES"; break;\r
3383                 }\r
3384                 if (s->supported_ciphers_mask & (1 << s->cipher_type))\r
3385                     cipher_chosen = 1;\r
3386             }\r
3387         }\r
3388         if (!cipher_chosen) {\r
3389             if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0)\r
3390                 bombout(("Server violates SSH-1 protocol by not "\r
3391                          "supporting 3DES encryption"));\r
3392             else\r
3393                 /* shouldn't happen */\r
3394                 bombout(("No supported ciphers found"));\r
3395             crStop(0);\r
3396         }\r
3398         /* Warn about chosen cipher if necessary. */\r
3399         if (warn) {\r
3400             ssh_set_frozen(ssh, 1);\r
3401             s->dlgret = askalg(ssh->frontend, "cipher", cipher_string,\r
3402                                ssh_dialog_callback, ssh);\r
3403             if (s->dlgret < 0) {\r
3404                 do {\r
3405                     crReturn(0);\r
3406                     if (pktin) {\r
3407                         bombout(("Unexpected data from server while waiting"\r
3408                                  " for user response"));\r
3409                         crStop(0);\r
3410                     }\r
3411                 } while (pktin || inlen > 0);\r
3412                 s->dlgret = ssh->user_response;\r
3413             }\r
3414             ssh_set_frozen(ssh, 0);\r
3415             if (s->dlgret == 0) {\r
3416                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
3417                                0, TRUE);\r
3418                 crStop(0);\r
3419             }\r
3420         }\r
3421     }\r
3423     switch (s->cipher_type) {\r
3424       case SSH_CIPHER_3DES:\r
3425         logevent("Using 3DES encryption");\r
3426         break;\r
3427       case SSH_CIPHER_DES:\r
3428         logevent("Using single-DES encryption");\r
3429         break;\r
3430       case SSH_CIPHER_BLOWFISH:\r
3431         logevent("Using Blowfish encryption");\r
3432         break;\r
3433     }\r
3435     send_packet(ssh, SSH1_CMSG_SESSION_KEY,\r
3436                 PKT_CHAR, s->cipher_type,\r
3437                 PKT_DATA, cookie, 8,\r
3438                 PKT_CHAR, (s->len * 8) >> 8, PKT_CHAR, (s->len * 8) & 0xFF,\r
3439                 PKT_DATA, s->rsabuf, s->len,\r
3440                 PKT_INT, ssh->v1_local_protoflags, PKT_END);\r
3442     logevent("Trying to enable encryption...");\r
3444     sfree(s->rsabuf);\r
3446     ssh->cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :\r
3447                    s->cipher_type == SSH_CIPHER_DES ? &ssh_des :\r
3448                    &ssh_3des);\r
3449     ssh->v1_cipher_ctx = ssh->cipher->make_context();\r
3450     ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key);\r
3451     logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name);\r
3453     ssh->crcda_ctx = crcda_make_context();\r
3454     logevent("Installing CRC compensation attack detector");\r
3456     if (servkey.modulus) {\r
3457         sfree(servkey.modulus);\r
3458         servkey.modulus = NULL;\r
3459     }\r
3460     if (servkey.exponent) {\r
3461         sfree(servkey.exponent);\r
3462         servkey.exponent = NULL;\r
3463     }\r
3464     if (hostkey.modulus) {\r
3465         sfree(hostkey.modulus);\r
3466         hostkey.modulus = NULL;\r
3467     }\r
3468     if (hostkey.exponent) {\r
3469         sfree(hostkey.exponent);\r
3470         hostkey.exponent = NULL;\r
3471     }\r
3472     crWaitUntil(pktin);\r
3474     if (pktin->type != SSH1_SMSG_SUCCESS) {\r
3475         bombout(("Encryption not successfully enabled"));\r
3476         crStop(0);\r
3477     }\r
3479     logevent("Successfully started encryption");\r
3481     fflush(stdout); /* FIXME eh? */\r
3482     {\r
3483         if (!get_remote_username(&ssh->cfg, s->username,\r
3484                                  sizeof(s->username))) {\r
3485             int ret; /* need not be kept over crReturn */\r
3486             s->cur_prompt = new_prompts(ssh->frontend);\r
3487             s->cur_prompt->to_server = TRUE;\r
3488             s->cur_prompt->name = dupstr("SSH login name");\r
3489             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE,\r
3490                        lenof(s->username)); \r
3491             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
3492             while (ret < 0) {\r
3493                 ssh->send_ok = 1;\r
3494                 crWaitUntil(!pktin);\r
3495                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
3496                 ssh->send_ok = 0;\r
3497             }\r
3498             if (!ret) {\r
3499                 /*\r
3500                  * Failed to get a username. Terminate.\r
3501                  */\r
3502                 free_prompts(s->cur_prompt);\r
3503                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
3504                 crStop(0);\r
3505             }\r
3506             memcpy(s->username, s->cur_prompt->prompts[0]->result,\r
3507                    lenof(s->username));\r
3508             free_prompts(s->cur_prompt);\r
3509         }\r
3511         send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END);\r
3512         {\r
3513             char *userlog = dupprintf("Sent username \"%s\"", s->username);\r
3514             logevent(userlog);\r
3515             if (flags & FLAG_INTERACTIVE &&\r
3516                 (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {\r
3517                 c_write_str(ssh, userlog);\r
3518                 c_write_str(ssh, "\r\n");\r
3519             }\r
3520             sfree(userlog);\r
3521         }\r
3522     }\r
3524     crWaitUntil(pktin);\r
3526     if ((s->supported_auths_mask & (1 << SSH1_AUTH_RSA)) == 0) {\r
3527         /* We must not attempt PK auth. Pretend we've already tried it. */\r
3528         s->tried_publickey = s->tried_agent = 1;\r
3529     } else {\r
3530         s->tried_publickey = s->tried_agent = 0;\r
3531     }\r
3532     s->tis_auth_refused = s->ccard_auth_refused = 0;\r
3533     /*\r
3534      * Load the public half of any configured keyfile for later use.\r
3535      */\r
3536     if (!filename_is_null(ssh->cfg.keyfile)) {\r
3537         int keytype;\r
3538         logeventf(ssh, "Reading private key file \"%.150s\"",\r
3539                   filename_to_str(&ssh->cfg.keyfile));\r
3540         keytype = key_type(&ssh->cfg.keyfile);\r
3541         if (keytype == SSH_KEYTYPE_SSH1) {\r
3542             const char *error;\r
3543             if (rsakey_pubblob(&ssh->cfg.keyfile,\r
3544                                &s->publickey_blob, &s->publickey_bloblen,\r
3545                                &s->publickey_comment, &error)) {\r
3546                 s->publickey_encrypted = rsakey_encrypted(&ssh->cfg.keyfile,\r
3547                                                           NULL);\r
3548             } else {\r
3549                 char *msgbuf;\r
3550                 logeventf(ssh, "Unable to load private key (%s)", error);\r
3551                 msgbuf = dupprintf("Unable to load private key file "\r
3552                                    "\"%.150s\" (%s)\r\n",\r
3553                                    filename_to_str(&ssh->cfg.keyfile),\r
3554                                    error);\r
3555                 c_write_str(ssh, msgbuf);\r
3556                 sfree(msgbuf);\r
3557                 s->publickey_blob = NULL;\r
3558             }\r
3559         } else {\r
3560             char *msgbuf;\r
3561             logeventf(ssh, "Unable to use this key file (%s)",\r
3562                       key_type_to_str(keytype));\r
3563             msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
3564                                " (%s)\r\n",\r
3565                                filename_to_str(&ssh->cfg.keyfile),\r
3566                                key_type_to_str(keytype));\r
3567             c_write_str(ssh, msgbuf);\r
3568             sfree(msgbuf);\r
3569             s->publickey_blob = NULL;\r
3570         }\r
3571     } else\r
3572         s->publickey_blob = NULL;\r
3574     while (pktin->type == SSH1_SMSG_FAILURE) {\r
3575         s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;\r
3577         if (ssh->cfg.tryagent && agent_exists() && !s->tried_agent) {\r
3578             /*\r
3579              * Attempt RSA authentication using Pageant.\r
3580              */\r
3581             void *r;\r
3583             s->authed = FALSE;\r
3584             s->tried_agent = 1;\r
3585             logevent("Pageant is running. Requesting keys.");\r
3587             /* Request the keys held by the agent. */\r
3588             PUT_32BIT(s->request, 1);\r
3589             s->request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;\r
3590             if (!agent_query(s->request, 5, &r, &s->responselen,\r
3591                              ssh_agent_callback, ssh)) {\r
3592                 do {\r
3593                     crReturn(0);\r
3594                     if (pktin) {\r
3595                         bombout(("Unexpected data from server while waiting"\r
3596                                  " for agent response"));\r
3597                         crStop(0);\r
3598                     }\r
3599                 } while (pktin || inlen > 0);\r
3600                 r = ssh->agent_response;\r
3601                 s->responselen = ssh->agent_response_len;\r
3602             }\r
3603             s->response = (unsigned char *) r;\r
3604             if (s->response && s->responselen >= 5 &&\r
3605                 s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {\r
3606                 s->p = s->response + 5;\r
3607                 s->nkeys = GET_32BIT(s->p);\r
3608                 s->p += 4;\r
3609                 logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys);\r
3610                 for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {\r
3611                     unsigned char *pkblob = s->p;\r
3612                     s->p += 4;\r
3613                     {\r
3614                         int n, ok = FALSE;\r
3615                         do {           /* do while (0) to make breaking easy */\r
3616                             n = ssh1_read_bignum\r
3617                                 (s->p, s->responselen-(s->p-s->response),\r
3618                                  &s->key.exponent);\r
3619                             if (n < 0)\r
3620                                 break;\r
3621                             s->p += n;\r
3622                             n = ssh1_read_bignum\r
3623                                 (s->p, s->responselen-(s->p-s->response),\r
3624                                  &s->key.modulus);\r
3625                             if (n < 0)\r
3626                             break;\r
3627                             s->p += n;\r
3628                             if (s->responselen - (s->p-s->response) < 4)\r
3629                                 break;\r
3630                             s->commentlen = GET_32BIT(s->p);\r
3631                             s->p += 4;\r
3632                             if (s->responselen - (s->p-s->response) <\r
3633                                 s->commentlen)\r
3634                                 break;\r
3635                             s->commentp = (char *)s->p;\r
3636                             s->p += s->commentlen;\r
3637                             ok = TRUE;\r
3638                         } while (0);\r
3639                         if (!ok) {\r
3640                             logevent("Pageant key list packet was truncated");\r
3641                             break;\r
3642                         }\r
3643                     }\r
3644                     if (s->publickey_blob) {\r
3645                         if (!memcmp(pkblob, s->publickey_blob,\r
3646                                     s->publickey_bloblen)) {\r
3647                             logeventf(ssh, "Pageant key #%d matches "\r
3648                                       "configured key file", s->keyi);\r
3649                             s->tried_publickey = 1;\r
3650                         } else\r
3651                             /* Skip non-configured key */\r
3652                             continue;\r
3653                     }\r
3654                     logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
3655                     send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
3656                                 PKT_BIGNUM, s->key.modulus, PKT_END);\r
3657                     crWaitUntil(pktin);\r
3658                     if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
3659                         logevent("Key refused");\r
3660                         continue;\r
3661                     }\r
3662                     logevent("Received RSA challenge");\r
3663                     if ((s->challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
3664                         bombout(("Server's RSA challenge was badly formatted"));\r
3665                         crStop(0);\r
3666                     }\r
3668                     {\r
3669                         char *agentreq, *q, *ret;\r
3670                         void *vret;\r
3671                         int len, retlen;\r
3672                         len = 1 + 4;   /* message type, bit count */\r
3673                         len += ssh1_bignum_length(s->key.exponent);\r
3674                         len += ssh1_bignum_length(s->key.modulus);\r
3675                         len += ssh1_bignum_length(s->challenge);\r
3676                         len += 16;     /* session id */\r
3677                         len += 4;      /* response format */\r
3678                         agentreq = snewn(4 + len, char);\r
3679                         PUT_32BIT(agentreq, len);\r
3680                         q = agentreq + 4;\r
3681                         *q++ = SSH1_AGENTC_RSA_CHALLENGE;\r
3682                         PUT_32BIT(q, bignum_bitcount(s->key.modulus));\r
3683                         q += 4;\r
3684                         q += ssh1_write_bignum(q, s->key.exponent);\r
3685                         q += ssh1_write_bignum(q, s->key.modulus);\r
3686                         q += ssh1_write_bignum(q, s->challenge);\r
3687                         memcpy(q, s->session_id, 16);\r
3688                         q += 16;\r
3689                         PUT_32BIT(q, 1);        /* response format */\r
3690                         if (!agent_query(agentreq, len + 4, &vret, &retlen,\r
3691                                          ssh_agent_callback, ssh)) {\r
3692                             sfree(agentreq);\r
3693                             do {\r
3694                                 crReturn(0);\r
3695                                 if (pktin) {\r
3696                                     bombout(("Unexpected data from server"\r
3697                                              " while waiting for agent"\r
3698                                              " response"));\r
3699                                     crStop(0);\r
3700                                 }\r
3701                             } while (pktin || inlen > 0);\r
3702                             vret = ssh->agent_response;\r
3703                             retlen = ssh->agent_response_len;\r
3704                         } else\r
3705                             sfree(agentreq);\r
3706                         ret = vret;\r
3707                         if (ret) {\r
3708                             if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {\r
3709                                 logevent("Sending Pageant's response");\r
3710                                 send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
3711                                             PKT_DATA, ret + 5, 16,\r
3712                                             PKT_END);\r
3713                                 sfree(ret);\r
3714                                 crWaitUntil(pktin);\r
3715                                 if (pktin->type == SSH1_SMSG_SUCCESS) {\r
3716                                     logevent\r
3717                                         ("Pageant's response accepted");\r
3718                                     if (flags & FLAG_VERBOSE) {\r
3719                                         c_write_str(ssh, "Authenticated using"\r
3720                                                     " RSA key \"");\r
3721                                         c_write(ssh, s->commentp,\r
3722                                                 s->commentlen);\r
3723                                         c_write_str(ssh, "\" from agent\r\n");\r
3724                                     }\r
3725                                     s->authed = TRUE;\r
3726                                 } else\r
3727                                     logevent\r
3728                                         ("Pageant's response not accepted");\r
3729                             } else {\r
3730                                 logevent\r
3731                                     ("Pageant failed to answer challenge");\r
3732                                 sfree(ret);\r
3733                             }\r
3734                         } else {\r
3735                             logevent("No reply received from Pageant");\r
3736                         }\r
3737                     }\r
3738                     freebn(s->key.exponent);\r
3739                     freebn(s->key.modulus);\r
3740                     freebn(s->challenge);\r
3741                     if (s->authed)\r
3742                         break;\r
3743                 }\r
3744                 sfree(s->response);\r
3745                 if (s->publickey_blob && !s->tried_publickey)\r
3746                     logevent("Configured key file not in Pageant");\r
3747             } else {\r
3748                 logevent("Failed to get reply from Pageant");\r
3749             }\r
3750             if (s->authed)\r
3751                 break;\r
3752         }\r
3753         if (s->publickey_blob && !s->tried_publickey) {\r
3754             /*\r
3755              * Try public key authentication with the specified\r
3756              * key file.\r
3757              */\r
3758             int got_passphrase; /* need not be kept over crReturn */\r
3759             if (flags & FLAG_VERBOSE)\r
3760                 c_write_str(ssh, "Trying public key authentication.\r\n");\r
3761             logeventf(ssh, "Trying public key \"%s\"",\r
3762                       filename_to_str(&ssh->cfg.keyfile));\r
3763             s->tried_publickey = 1;\r
3764             got_passphrase = FALSE;\r
3765             while (!got_passphrase) {\r
3766                 /*\r
3767                  * Get a passphrase, if necessary.\r
3768                  */\r
3769                 char *passphrase = NULL;    /* only written after crReturn */\r
3770                 const char *error;\r
3771                 if (!s->publickey_encrypted) {\r
3772                     if (flags & FLAG_VERBOSE)\r
3773                         c_write_str(ssh, "No passphrase required.\r\n");\r
3774                     passphrase = NULL;\r
3775                 } else {\r
3776                     int ret; /* need not be kept over crReturn */\r
3777                     s->cur_prompt = new_prompts(ssh->frontend);\r
3778                     s->cur_prompt->to_server = FALSE;\r
3779                     s->cur_prompt->name = dupstr("SSH key passphrase");\r
3780                     add_prompt(s->cur_prompt,\r
3781                                dupprintf("Passphrase for key \"%.100s\": ",\r
3782                                          s->publickey_comment),\r
3783                                FALSE, SSH_MAX_PASSWORD_LEN);\r
3784                     ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
3785                     while (ret < 0) {\r
3786                         ssh->send_ok = 1;\r
3787                         crWaitUntil(!pktin);\r
3788                         ret = get_userpass_input(s->cur_prompt, in, inlen);\r
3789                         ssh->send_ok = 0;\r
3790                     }\r
3791                     if (!ret) {\r
3792                         /* Failed to get a passphrase. Terminate. */\r
3793                         free_prompts(s->cur_prompt);\r
3794                         ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
3795                                        0, TRUE);\r
3796                         crStop(0);\r
3797                     }\r
3798                     passphrase = dupstr(s->cur_prompt->prompts[0]->result);\r
3799                     free_prompts(s->cur_prompt);\r
3800                 }\r
3801                 /*\r
3802                  * Try decrypting key with passphrase.\r
3803                  */\r
3804                 ret = loadrsakey(&ssh->cfg.keyfile, &s->key, passphrase,\r
3805                                  &error);\r
3806                 if (passphrase) {\r
3807                     memset(passphrase, 0, strlen(passphrase));\r
3808                     sfree(passphrase);\r
3809                 }\r
3810                 if (ret == 1) {\r
3811                     /* Correct passphrase. */\r
3812                     got_passphrase = TRUE;\r
3813                 } else if (ret == 0) {\r
3814                     c_write_str(ssh, "Couldn't load private key from ");\r
3815                     c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile));\r
3816                     c_write_str(ssh, " (");\r
3817                     c_write_str(ssh, error);\r
3818                     c_write_str(ssh, ").\r\n");\r
3819                     got_passphrase = FALSE;\r
3820                     break;             /* go and try something else */\r
3821                 } else if (ret == -1) {\r
3822                     c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */\r
3823                     got_passphrase = FALSE;\r
3824                     /* and try again */\r
3825                 } else {\r
3826                     assert(0 && "unexpected return from loadrsakey()");\r
3827                     got_passphrase = FALSE;   /* placate optimisers */\r
3828                 }\r
3829             }\r
3831             if (got_passphrase) {\r
3833                 /*\r
3834                  * Send a public key attempt.\r
3835                  */\r
3836                 send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
3837                             PKT_BIGNUM, s->key.modulus, PKT_END);\r
3839                 crWaitUntil(pktin);\r
3840                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
3841                     c_write_str(ssh, "Server refused our public key.\r\n");\r
3842                     continue;          /* go and try something else */\r
3843                 }\r
3844                 if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
3845                     bombout(("Bizarre response to offer of public key"));\r
3846                     crStop(0);\r
3847                 }\r
3849                 {\r
3850                     int i;\r
3851                     unsigned char buffer[32];\r
3852                     Bignum challenge, response;\r
3854                     if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
3855                         bombout(("Server's RSA challenge was badly formatted"));\r
3856                         crStop(0);\r
3857                     }\r
3858                     response = rsadecrypt(challenge, &s->key);\r
3859                     freebn(s->key.private_exponent);/* burn the evidence */\r
3861                     for (i = 0; i < 32; i++) {\r
3862                         buffer[i] = bignum_byte(response, 31 - i);\r
3863                     }\r
3865                     MD5Init(&md5c);\r
3866                     MD5Update(&md5c, buffer, 32);\r
3867                     MD5Update(&md5c, s->session_id, 16);\r
3868                     MD5Final(buffer, &md5c);\r
3870                     send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
3871                                 PKT_DATA, buffer, 16, PKT_END);\r
3873                     freebn(challenge);\r
3874                     freebn(response);\r
3875                 }\r
3877                 crWaitUntil(pktin);\r
3878                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
3879                     if (flags & FLAG_VERBOSE)\r
3880                         c_write_str(ssh, "Failed to authenticate with"\r
3881                                     " our public key.\r\n");\r
3882                     continue;          /* go and try something else */\r
3883                 } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
3884                     bombout(("Bizarre response to RSA authentication response"));\r
3885                     crStop(0);\r
3886                 }\r
3888                 break;                 /* we're through! */\r
3889             }\r
3891         }\r
3893         /*\r
3894          * Otherwise, try various forms of password-like authentication.\r
3895          */\r
3896         s->cur_prompt = new_prompts(ssh->frontend);\r
3898         if (ssh->cfg.try_tis_auth &&\r
3899             (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&\r
3900             !s->tis_auth_refused) {\r
3901             s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;\r
3902             logevent("Requested TIS authentication");\r
3903             send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END);\r
3904             crWaitUntil(pktin);\r
3905             if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {\r
3906                 logevent("TIS authentication declined");\r
3907                 if (flags & FLAG_INTERACTIVE)\r
3908                     c_write_str(ssh, "TIS authentication refused.\r\n");\r
3909                 s->tis_auth_refused = 1;\r
3910                 continue;\r
3911             } else {\r
3912                 char *challenge;\r
3913                 int challengelen;\r
3914                 char *instr_suf, *prompt;\r
3916                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
3917                 if (!challenge) {\r
3918                     bombout(("TIS challenge packet was badly formed"));\r
3919                     crStop(0);\r
3920                 }\r
3921                 logevent("Received TIS challenge");\r
3922                 s->cur_prompt->to_server = TRUE;\r
3923                 s->cur_prompt->name = dupstr("SSH TIS authentication");\r
3924                 /* Prompt heuristic comes from OpenSSH */\r
3925                 if (memchr(challenge, '\n', challengelen)) {\r
3926                     instr_suf = dupstr("");\r
3927                     prompt = dupprintf("%.*s", challengelen, challenge);\r
3928                 } else {\r
3929                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
3930                     prompt = dupstr("Response: ");\r
3931                 }\r
3932                 s->cur_prompt->instruction =\r
3933                     dupprintf("Using TIS authentication.%s%s",\r
3934                               (*instr_suf) ? "\n" : "",\r
3935                               instr_suf);\r
3936                 s->cur_prompt->instr_reqd = TRUE;\r
3937                 add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);\r
3938                 sfree(instr_suf);\r
3939             }\r
3940         }\r
3941         if (ssh->cfg.try_tis_auth &&\r
3942             (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&\r
3943             !s->ccard_auth_refused) {\r
3944             s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;\r
3945             logevent("Requested CryptoCard authentication");\r
3946             send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END);\r
3947             crWaitUntil(pktin);\r
3948             if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {\r
3949                 logevent("CryptoCard authentication declined");\r
3950                 c_write_str(ssh, "CryptoCard authentication refused.\r\n");\r
3951                 s->ccard_auth_refused = 1;\r
3952                 continue;\r
3953             } else {\r
3954                 char *challenge;\r
3955                 int challengelen;\r
3956                 char *instr_suf, *prompt;\r
3958                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
3959                 if (!challenge) {\r
3960                     bombout(("CryptoCard challenge packet was badly formed"));\r
3961                     crStop(0);\r
3962                 }\r
3963                 logevent("Received CryptoCard challenge");\r
3964                 s->cur_prompt->to_server = TRUE;\r
3965                 s->cur_prompt->name = dupstr("SSH CryptoCard authentication");\r
3966                 s->cur_prompt->name_reqd = FALSE;\r
3967                 /* Prompt heuristic comes from OpenSSH */\r
3968                 if (memchr(challenge, '\n', challengelen)) {\r
3969                     instr_suf = dupstr("");\r
3970                     prompt = dupprintf("%.*s", challengelen, challenge);\r
3971                 } else {\r
3972                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
3973                     prompt = dupstr("Response: ");\r
3974                 }\r
3975                 s->cur_prompt->instruction =\r
3976                     dupprintf("Using CryptoCard authentication.%s%s",\r
3977                               (*instr_suf) ? "\n" : "",\r
3978                               instr_suf);\r
3979                 s->cur_prompt->instr_reqd = TRUE;\r
3980                 add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);\r
3981                 sfree(instr_suf);\r
3982             }\r
3983         }\r
3984         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
3985             if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) {\r
3986                 bombout(("No supported authentication methods available"));\r
3987                 crStop(0);\r
3988             }\r
3989             s->cur_prompt->to_server = TRUE;\r
3990             s->cur_prompt->name = dupstr("SSH password");\r
3991             add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ",\r
3992                                                 s->username, ssh->savedhost),\r
3993                        FALSE, SSH_MAX_PASSWORD_LEN);\r
3994         }\r
3996         /*\r
3997          * Show password prompt, having first obtained it via a TIS\r
3998          * or CryptoCard exchange if we're doing TIS or CryptoCard\r
3999          * authentication.\r
4000          */\r
4001         {\r
4002             int ret; /* need not be kept over crReturn */\r
4003             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
4004             while (ret < 0) {\r
4005                 ssh->send_ok = 1;\r
4006                 crWaitUntil(!pktin);\r
4007                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
4008                 ssh->send_ok = 0;\r
4009             }\r
4010             if (!ret) {\r
4011                 /*\r
4012                  * Failed to get a password (for example\r
4013                  * because one was supplied on the command line\r
4014                  * which has already failed to work). Terminate.\r
4015                  */\r
4016                 free_prompts(s->cur_prompt);\r
4017                 ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE);\r
4018                 crStop(0);\r
4019             }\r
4020         }\r
4022         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
4023             /*\r
4024              * Defence against traffic analysis: we send a\r
4025              * whole bunch of packets containing strings of\r
4026              * different lengths. One of these strings is the\r
4027              * password, in a SSH1_CMSG_AUTH_PASSWORD packet.\r
4028              * The others are all random data in\r
4029              * SSH1_MSG_IGNORE packets. This way a passive\r
4030              * listener can't tell which is the password, and\r
4031              * hence can't deduce the password length.\r
4032              * \r
4033              * Anybody with a password length greater than 16\r
4034              * bytes is going to have enough entropy in their\r
4035              * password that a listener won't find it _that_\r
4036              * much help to know how long it is. So what we'll\r
4037              * do is:\r
4038              * \r
4039              *  - if password length < 16, we send 15 packets\r
4040              *    containing string lengths 1 through 15\r
4041              * \r
4042              *  - otherwise, we let N be the nearest multiple\r
4043              *    of 8 below the password length, and send 8\r
4044              *    packets containing string lengths N through\r
4045              *    N+7. This won't obscure the order of\r
4046              *    magnitude of the password length, but it will\r
4047              *    introduce a bit of extra uncertainty.\r
4048              * \r
4049              * A few servers can't deal with SSH1_MSG_IGNORE, at\r
4050              * least in this context. For these servers, we need\r
4051              * an alternative defence. We make use of the fact\r
4052              * that the password is interpreted as a C string:\r
4053              * so we can append a NUL, then some random data.\r
4054              * \r
4055              * A few servers can deal with neither SSH1_MSG_IGNORE\r
4056              * here _nor_ a padded password string.\r
4057              * For these servers we are left with no defences\r
4058              * against password length sniffing.\r
4059              */\r
4060             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) &&\r
4061                 !(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
4062                 /*\r
4063                  * The server can deal with SSH1_MSG_IGNORE, so\r
4064                  * we can use the primary defence.\r
4065                  */\r
4066                 int bottom, top, pwlen, i;\r
4067                 char *randomstr;\r
4069                 pwlen = strlen(s->cur_prompt->prompts[0]->result);\r
4070                 if (pwlen < 16) {\r
4071                     bottom = 0;    /* zero length passwords are OK! :-) */\r
4072                     top = 15;\r
4073                 } else {\r
4074                     bottom = pwlen & ~7;\r
4075                     top = bottom + 7;\r
4076                 }\r
4078                 assert(pwlen >= bottom && pwlen <= top);\r
4080                 randomstr = snewn(top + 1, char);\r
4082                 for (i = bottom; i <= top; i++) {\r
4083                     if (i == pwlen) {\r
4084                         defer_packet(ssh, s->pwpkt_type,\r
4085                                      PKTT_PASSWORD, PKT_STR,\r
4086                                      s->cur_prompt->prompts[0]->result,\r
4087                                      PKTT_OTHER, PKT_END);\r
4088                     } else {\r
4089                         for (j = 0; j < i; j++) {\r
4090                             do {\r
4091                                 randomstr[j] = random_byte();\r
4092                             } while (randomstr[j] == '\0');\r
4093                         }\r
4094                         randomstr[i] = '\0';\r
4095                         defer_packet(ssh, SSH1_MSG_IGNORE,\r
4096                                      PKT_STR, randomstr, PKT_END);\r
4097                     }\r
4098                 }\r
4099                 logevent("Sending password with camouflage packets");\r
4100                 ssh_pkt_defersend(ssh);\r
4101                 sfree(randomstr);\r
4102             } \r
4103             else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
4104                 /*\r
4105                  * The server can't deal with SSH1_MSG_IGNORE\r
4106                  * but can deal with padded passwords, so we\r
4107                  * can use the secondary defence.\r
4108                  */\r
4109                 char string[64];\r
4110                 char *ss;\r
4111                 int len;\r
4113                 len = strlen(s->cur_prompt->prompts[0]->result);\r
4114                 if (len < sizeof(string)) {\r
4115                     ss = string;\r
4116                     strcpy(string, s->cur_prompt->prompts[0]->result);\r
4117                     len++;             /* cover the zero byte */\r
4118                     while (len < sizeof(string)) {\r
4119                         string[len++] = (char) random_byte();\r
4120                     }\r
4121                 } else {\r
4122                     ss = s->cur_prompt->prompts[0]->result;\r
4123                 }\r
4124                 logevent("Sending length-padded password");\r
4125                 send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,\r
4126                             PKT_INT, len, PKT_DATA, ss, len,\r
4127                             PKTT_OTHER, PKT_END);\r
4128             } else {\r
4129                 /*\r
4130                  * The server is believed unable to cope with\r
4131                  * any of our password camouflage methods.\r
4132                  */\r
4133                 int len;\r
4134                 len = strlen(s->cur_prompt->prompts[0]->result);\r
4135                 logevent("Sending unpadded password");\r
4136                 send_packet(ssh, s->pwpkt_type,\r
4137                             PKTT_PASSWORD, PKT_INT, len,\r
4138                             PKT_DATA, s->cur_prompt->prompts[0]->result, len,\r
4139                             PKTT_OTHER, PKT_END);\r
4140             }\r
4141         } else {\r
4142             send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,\r
4143                         PKT_STR, s->cur_prompt->prompts[0]->result,\r
4144                         PKTT_OTHER, PKT_END);\r
4145         }\r
4146         logevent("Sent password");\r
4147         free_prompts(s->cur_prompt);\r
4148         crWaitUntil(pktin);\r
4149         if (pktin->type == SSH1_SMSG_FAILURE) {\r
4150             if (flags & FLAG_VERBOSE)\r
4151                 c_write_str(ssh, "Access denied\r\n");\r
4152             logevent("Authentication refused");\r
4153         } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
4154             bombout(("Strange packet received, type %d", pktin->type));\r
4155             crStop(0);\r
4156         }\r
4157     }\r
4159     /* Clear up */\r
4160     if (s->publickey_blob) {\r
4161         sfree(s->publickey_blob);\r
4162         sfree(s->publickey_comment);\r
4163     }\r
4165     logevent("Authentication successful");\r
4167     crFinish(1);\r
4170 void sshfwd_close(struct ssh_channel *c)\r
4172     Ssh ssh = c->ssh;\r
4174     if (ssh->state == SSH_STATE_CLOSED)\r
4175         return;\r
4177     if (!c->closes) {\r
4178         /*\r
4179          * If halfopen is true, we have sent\r
4180          * CHANNEL_OPEN for this channel, but it hasn't even been\r
4181          * acknowledged by the server. So we must set a close flag\r
4182          * on it now, and then when the server acks the channel\r
4183          * open, we can close it then.\r
4184          */\r
4185         if (!c->halfopen) {\r
4186             if (ssh->version == 1) {\r
4187                 send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,\r
4188                             PKT_END);\r
4189                 c->closes = 1;                 /* sent MSG_CLOSE */\r
4190             } else {\r
4191                 int bytes_to_send = bufchain_size(&c->v.v2.outbuffer);\r
4192                 if (bytes_to_send > 0) {\r
4193                     /*\r
4194                      * If we still have unsent data in our outgoing\r
4195                      * buffer for this channel, we can't actually\r
4196                      * initiate a close operation yet or that data\r
4197                      * will be lost. Instead, set the pending_close\r
4198                      * flag so that when we do clear the buffer\r
4199                      * we'll start closing the channel.\r
4200                      */\r
4201                     char logmsg[160] = {'\0'};\r
4202                     sprintf(\r
4203                             logmsg,\r
4204                             "Forwarded port pending to be closed : "\r
4205                             "%d bytes remaining",\r
4206                             bytes_to_send);\r
4207                     logevent(logmsg);\r
4209                     c->pending_close = TRUE;\r
4210                 } else {\r
4211                     /*\r
4212                      * No locally buffered data, so we can send the\r
4213                      * close message immediately.\r
4214                      */\r
4215                     struct Packet *pktout;\r
4216                     pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
4217                     ssh2_pkt_adduint32(pktout, c->remoteid);\r
4218                     ssh2_pkt_send(ssh, pktout);\r
4219                     c->closes = 1;                     /* sent MSG_CLOSE */\r
4220                     logevent("Nothing left to send, closing channel");\r
4221                 }\r
4222             }\r
4223         }\r
4225         if (c->type == CHAN_X11) {\r
4226             c->u.x11.s = NULL;\r
4227             logevent("Forwarded X11 connection terminated");\r
4228         } else if (c->type == CHAN_SOCKDATA ||\r
4229                    c->type == CHAN_SOCKDATA_DORMANT) {\r
4230             c->u.pfd.s = NULL;\r
4231             logevent("Forwarded port closed");\r
4232         }\r
4233     }\r
4236 int sshfwd_write(struct ssh_channel *c, char *buf, int len)\r
4238     Ssh ssh = c->ssh;\r
4240     if (ssh->state == SSH_STATE_CLOSED)\r
4241         return 0;\r
4243     if (ssh->version == 1) {\r
4244         send_packet(ssh, SSH1_MSG_CHANNEL_DATA,\r
4245                     PKT_INT, c->remoteid,\r
4246                     PKT_INT, len, PKTT_DATA, PKT_DATA, buf, len,\r
4247                     PKTT_OTHER, PKT_END);\r
4248         /*\r
4249          * In SSH-1 we can return 0 here - implying that forwarded\r
4250          * connections are never individually throttled - because\r
4251          * the only circumstance that can cause throttling will be\r
4252          * the whole SSH connection backing up, in which case\r
4253          * _everything_ will be throttled as a whole.\r
4254          */\r
4255         return 0;\r
4256     } else {\r
4257         ssh2_add_channel_data(c, buf, len);\r
4258         return ssh2_try_send(c);\r
4259     }\r
4262 void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)\r
4264     Ssh ssh = c->ssh;\r
4265     int buflimit;\r
4267     if (ssh->state == SSH_STATE_CLOSED)\r
4268         return;\r
4270     if (ssh->version == 1) {\r
4271         buflimit = SSH1_BUFFER_LIMIT;\r
4272     } else {\r
4273         buflimit = c->v.v2.locmaxwin;\r
4274         ssh2_set_window(c, bufsize < buflimit ? buflimit - bufsize : 0);\r
4275     }\r
4276     if (c->throttling_conn && bufsize <= buflimit) {\r
4277         c->throttling_conn = 0;\r
4278         ssh_throttle_conn(ssh, -1);\r
4279     }\r
4282 static void ssh_queueing_handler(Ssh ssh, struct Packet *pktin)\r
4284     struct queued_handler *qh = ssh->qhead;\r
4286     assert(qh != NULL);\r
4288     assert(pktin->type == qh->msg1 || pktin->type == qh->msg2);\r
4290     if (qh->msg1 > 0) {\r
4291         assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler);\r
4292         ssh->packet_dispatch[qh->msg1] = NULL;\r
4293     }\r
4294     if (qh->msg2 > 0) {\r
4295         assert(ssh->packet_dispatch[qh->msg2] == ssh_queueing_handler);\r
4296         ssh->packet_dispatch[qh->msg2] = NULL;\r
4297     }\r
4299     if (qh->next) {\r
4300         ssh->qhead = qh->next;\r
4302         if (ssh->qhead->msg1 > 0) {\r
4303             assert(ssh->packet_dispatch[ssh->qhead->msg1] == NULL);\r
4304             ssh->packet_dispatch[ssh->qhead->msg1] = ssh_queueing_handler;\r
4305         }\r
4306         if (ssh->qhead->msg2 > 0) {\r
4307             assert(ssh->packet_dispatch[ssh->qhead->msg2] == NULL);\r
4308             ssh->packet_dispatch[ssh->qhead->msg2] = ssh_queueing_handler;\r
4309         }\r
4310     } else {\r
4311         ssh->qhead = ssh->qtail = NULL;\r
4312         ssh->packet_dispatch[pktin->type] = NULL;\r
4313     }\r
4315     qh->handler(ssh, pktin, qh->ctx);\r
4317     sfree(qh);\r
4320 static void ssh_queue_handler(Ssh ssh, int msg1, int msg2,\r
4321                               chandler_fn_t handler, void *ctx)\r
4323     struct queued_handler *qh;\r
4325     qh = snew(struct queued_handler);\r
4326     qh->msg1 = msg1;\r
4327     qh->msg2 = msg2;\r
4328     qh->handler = handler;\r
4329     qh->ctx = ctx;\r
4330     qh->next = NULL;\r
4332     if (ssh->qtail == NULL) {\r
4333         ssh->qhead = qh;\r
4335         if (qh->msg1 > 0) {\r
4336             assert(ssh->packet_dispatch[qh->msg1] == NULL);\r
4337             ssh->packet_dispatch[qh->msg1] = ssh_queueing_handler;\r
4338         }\r
4339         if (qh->msg2 > 0) {\r
4340             assert(ssh->packet_dispatch[qh->msg2] == NULL);\r
4341             ssh->packet_dispatch[qh->msg2] = ssh_queueing_handler;\r
4342         }\r
4343     } else {\r
4344         ssh->qtail->next = qh;\r
4345     }\r
4346     ssh->qtail = qh;\r
4349 static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx)\r
4351     struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx;\r
4353     if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS :\r
4354                         SSH2_MSG_REQUEST_SUCCESS)) {\r
4355         logeventf(ssh, "Remote port forwarding from %s enabled",\r
4356                   pf->sportdesc);\r
4357     } else {\r
4358         logeventf(ssh, "Remote port forwarding from %s refused",\r
4359                   pf->sportdesc);\r
4361         rpf = del234(ssh->rportfwds, pf);\r
4362         assert(rpf == pf);\r
4363         pf->pfrec->remote = NULL;\r
4364         free_rportfwd(pf);\r
4365     }\r
4368 static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)\r
4370     const char *portfwd_strptr = cfg->portfwd;\r
4371     struct ssh_portfwd *epf;\r
4372     int i;\r
4374     if (!ssh->portfwds) {\r
4375         ssh->portfwds = newtree234(ssh_portcmp);\r
4376     } else {\r
4377         /*\r
4378          * Go through the existing port forwardings and tag them\r
4379          * with status==DESTROY. Any that we want to keep will be\r
4380          * re-enabled (status==KEEP) as we go through the\r
4381          * configuration and find out which bits are the same as\r
4382          * they were before.\r
4383          */\r
4384         struct ssh_portfwd *epf;\r
4385         int i;\r
4386         for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4387             epf->status = DESTROY;\r
4388     }\r
4390     while (*portfwd_strptr) {\r
4391         char address_family, type;\r
4392         int sport,dport,sserv,dserv;\r
4393         char sports[256], dports[256], saddr[256], host[256];\r
4394         int n;\r
4396         address_family = 'A';\r
4397         type = 'L';\r
4398         if (*portfwd_strptr == 'A' ||\r
4399             *portfwd_strptr == '4' ||\r
4400             *portfwd_strptr == '6')\r
4401             address_family = *portfwd_strptr++;\r
4402         if (*portfwd_strptr == 'L' ||\r
4403             *portfwd_strptr == 'R' ||\r
4404             *portfwd_strptr == 'D')\r
4405             type = *portfwd_strptr++;\r
4407         saddr[0] = '\0';\r
4409         n = 0;\r
4410         while (*portfwd_strptr && *portfwd_strptr != '\t') {\r
4411             if (*portfwd_strptr == ':') {\r
4412                 /*\r
4413                  * We've seen a colon in the middle of the\r
4414                  * source port number. This means that\r
4415                  * everything we've seen until now is the\r
4416                  * source _address_, so we'll move it into\r
4417                  * saddr and start sports from the beginning\r
4418                  * again.\r
4419                  */\r
4420                 portfwd_strptr++;\r
4421                 sports[n] = '\0';\r
4422                 if (ssh->version == 1 && type == 'R') {\r
4423                     logeventf(ssh, "SSH-1 cannot handle remote source address "\r
4424                               "spec \"%s\"; ignoring", sports);\r
4425                 } else\r
4426                     strcpy(saddr, sports);\r
4427                 n = 0;\r
4428             }\r
4429             if (n < lenof(sports)-1) sports[n++] = *portfwd_strptr++;\r
4430         }\r
4431         sports[n] = 0;\r
4432         if (type != 'D') {\r
4433             if (*portfwd_strptr == '\t')\r
4434                 portfwd_strptr++;\r
4435             n = 0;\r
4436             while (*portfwd_strptr && *portfwd_strptr != ':') {\r
4437                 if (n < lenof(host)-1) host[n++] = *portfwd_strptr++;\r
4438             }\r
4439             host[n] = 0;\r
4440             if (*portfwd_strptr == ':')\r
4441                 portfwd_strptr++;\r
4442             n = 0;\r
4443             while (*portfwd_strptr) {\r
4444                 if (n < lenof(dports)-1) dports[n++] = *portfwd_strptr++;\r
4445             }\r
4446             dports[n] = 0;\r
4447             portfwd_strptr++;\r
4448             dport = atoi(dports);\r
4449             dserv = 0;\r
4450             if (dport == 0) {\r
4451                 dserv = 1;\r
4452                 dport = net_service_lookup(dports);\r
4453                 if (!dport) {\r
4454                     logeventf(ssh, "Service lookup failed for destination"\r
4455                               " port \"%s\"", dports);\r
4456                 }\r
4457             }\r
4458         } else {\r
4459             while (*portfwd_strptr) portfwd_strptr++;\r
4460             host[0] = 0;\r
4461             dports[0] = 0;\r
4462             dport = dserv = -1;\r
4463             portfwd_strptr++;          /* eat the NUL and move to next one */\r
4464         }\r
4465         sport = atoi(sports);\r
4466         sserv = 0;\r
4467         if (sport == 0) {\r
4468             sserv = 1;\r
4469             sport = net_service_lookup(sports);\r
4470             if (!sport) {\r
4471                 logeventf(ssh, "Service lookup failed for source"\r
4472                           " port \"%s\"", sports);\r
4473             }\r
4474         }\r
4475         if (sport && dport) {\r
4476             /* Set up a description of the source port. */\r
4477             struct ssh_portfwd *pfrec, *epfrec;\r
4479             pfrec = snew(struct ssh_portfwd);\r
4480             pfrec->type = type;\r
4481             pfrec->saddr = *saddr ? dupstr(saddr) : NULL;\r
4482             pfrec->sserv = sserv ? dupstr(sports) : NULL;\r
4483             pfrec->sport = sport;\r
4484             pfrec->daddr = *host ? dupstr(host) : NULL;\r
4485             pfrec->dserv = dserv ? dupstr(dports) : NULL;\r
4486             pfrec->dport = dport;\r
4487             pfrec->local = NULL;\r
4488             pfrec->remote = NULL;\r
4489             pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :\r
4490                                     address_family == '6' ? ADDRTYPE_IPV6 :\r
4491                                     ADDRTYPE_UNSPEC);\r
4493             epfrec = add234(ssh->portfwds, pfrec);\r
4494             if (epfrec != pfrec) {\r
4495                 if (epfrec->status == DESTROY) {\r
4496                     /*\r
4497                      * We already have a port forwarding up and running\r
4498                      * with precisely these parameters. Hence, no need\r
4499                      * to do anything; simply re-tag the existing one\r
4500                      * as KEEP.\r
4501                      */\r
4502                     epfrec->status = KEEP;\r
4503                 }\r
4504                 /*\r
4505                  * Anything else indicates that there was a duplicate\r
4506                  * in our input, which we'll silently ignore.\r
4507                  */\r
4508                 free_portfwd(pfrec);\r
4509             } else {\r
4510                 pfrec->status = CREATE;\r
4511             }\r
4512         }\r
4513     }\r
4515     /*\r
4516      * Now go through and destroy any port forwardings which were\r
4517      * not re-enabled.\r
4518      */\r
4519     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4520         if (epf->status == DESTROY) {\r
4521             char *message;\r
4523             message = dupprintf("%s port forwarding from %s%s%d",\r
4524                                 epf->type == 'L' ? "local" :\r
4525                                 epf->type == 'R' ? "remote" : "dynamic",\r
4526                                 epf->saddr ? epf->saddr : "",\r
4527                                 epf->saddr ? ":" : "",\r
4528                                 epf->sport);\r
4530             if (epf->type != 'D') {\r
4531                 char *msg2 = dupprintf("%s to %s:%d", message,\r
4532                                        epf->daddr, epf->dport);\r
4533                 sfree(message);\r
4534                 message = msg2;\r
4535             }\r
4537             logeventf(ssh, "Cancelling %s", message);\r
4538             sfree(message);\r
4540             /* epf->remote or epf->local may be NULL if setting up a\r
4541              * forwarding failed. */\r
4542             if (epf->remote) {\r
4543                 struct ssh_rportfwd *rpf = epf->remote;\r
4544                 struct Packet *pktout;\r
4546                 /*\r
4547                  * Cancel the port forwarding at the server\r
4548                  * end.\r
4549                  */\r
4550                 if (ssh->version == 1) {\r
4551                     /*\r
4552                      * We cannot cancel listening ports on the\r
4553                      * server side in SSH-1! There's no message\r
4554                      * to support it. Instead, we simply remove\r
4555                      * the rportfwd record from the local end\r
4556                      * so that any connections the server tries\r
4557                      * to make on it are rejected.\r
4558                      */\r
4559                 } else {\r
4560                     pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
4561                     ssh2_pkt_addstring(pktout, "cancel-tcpip-forward");\r
4562                     ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */\r
4563                     if (epf->saddr) {\r
4564                         ssh2_pkt_addstring(pktout, epf->saddr);\r
4565                     } else if (ssh->cfg.rport_acceptall) {\r
4566                         /* XXX: ssh->cfg.rport_acceptall may not represent\r
4567                          * what was used to open the original connection,\r
4568                          * since it's reconfigurable. */\r
4569                         ssh2_pkt_addstring(pktout, "0.0.0.0");\r
4570                     } else {\r
4571                         ssh2_pkt_addstring(pktout, "127.0.0.1");\r
4572                     }\r
4573                     ssh2_pkt_adduint32(pktout, epf->sport);\r
4574                     ssh2_pkt_send(ssh, pktout);\r
4575                 }\r
4577                 del234(ssh->rportfwds, rpf);\r
4578                 free_rportfwd(rpf);\r
4579             } else if (epf->local) {\r
4580                 pfd_terminate(epf->local);\r
4581             }\r
4583             delpos234(ssh->portfwds, i);\r
4584             free_portfwd(epf);\r
4585             i--;                       /* so we don't skip one in the list */\r
4586         }\r
4588     /*\r
4589      * And finally, set up any new port forwardings (status==CREATE).\r
4590      */\r
4591     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
4592         if (epf->status == CREATE) {\r
4593             char *sportdesc, *dportdesc;\r
4594             sportdesc = dupprintf("%s%s%s%s%d%s",\r
4595                                   epf->saddr ? epf->saddr : "",\r
4596                                   epf->saddr ? ":" : "",\r
4597                                   epf->sserv ? epf->sserv : "",\r
4598                                   epf->sserv ? "(" : "",\r
4599                                   epf->sport,\r
4600                                   epf->sserv ? ")" : "");\r
4601             if (epf->type == 'D') {\r
4602                 dportdesc = NULL;\r
4603             } else {\r
4604                 dportdesc = dupprintf("%s:%s%s%d%s",\r
4605                                       epf->daddr,\r
4606                                       epf->dserv ? epf->dserv : "",\r
4607                                       epf->dserv ? "(" : "",\r
4608                                       epf->dport,\r
4609                                       epf->dserv ? ")" : "");\r
4610             }\r
4612             if (epf->type == 'L') {\r
4613                 const char *err = pfd_addforward(epf->daddr, epf->dport,\r
4614                                                  epf->saddr, epf->sport,\r
4615                                                  ssh, cfg,\r
4616                                                  &epf->local,\r
4617                                                  epf->addressfamily);\r
4619                 logeventf(ssh, "Local %sport %s forwarding to %s%s%s",\r
4620                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
4621                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
4622                           sportdesc, dportdesc,\r
4623                           err ? " failed: " : "", err ? err : "");\r
4624             } else if (epf->type == 'D') {\r
4625                 const char *err = pfd_addforward(NULL, -1,\r
4626                                                  epf->saddr, epf->sport,\r
4627                                                  ssh, cfg,\r
4628                                                  &epf->local,\r
4629                                                  epf->addressfamily);\r
4631                 logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",\r
4632                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
4633                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
4634                           sportdesc,\r
4635                           err ? " failed: " : "", err ? err : "");\r
4636             } else {\r
4637                 struct ssh_rportfwd *pf;\r
4639                 /*\r
4640                  * Ensure the remote port forwardings tree exists.\r
4641                  */\r
4642                 if (!ssh->rportfwds) {\r
4643                     if (ssh->version == 1)\r
4644                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);\r
4645                     else\r
4646                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);\r
4647                 }\r
4649                 pf = snew(struct ssh_rportfwd);\r
4650                 strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1);\r
4651                 pf->dhost[lenof(pf->dhost)-1] = '\0';\r
4652                 pf->dport = epf->dport;\r
4653                 pf->sport = epf->sport;\r
4654                 if (add234(ssh->rportfwds, pf) != pf) {\r
4655                     logeventf(ssh, "Duplicate remote port forwarding to %s:%d",\r
4656                               epf->daddr, epf->dport);\r
4657                     sfree(pf);\r
4658                 } else {\r
4659                     logeventf(ssh, "Requesting remote port %s"\r
4660                               " forward to %s", sportdesc, dportdesc);\r
4662                     pf->sportdesc = sportdesc;\r
4663                     sportdesc = NULL;\r
4664                     epf->remote = pf;\r
4665                     pf->pfrec = epf;\r
4667                     if (ssh->version == 1) {\r
4668                         send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST,\r
4669                                     PKT_INT, epf->sport,\r
4670                                     PKT_STR, epf->daddr,\r
4671                                     PKT_INT, epf->dport,\r
4672                                     PKT_END);\r
4673                         ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,\r
4674                                           SSH1_SMSG_FAILURE,\r
4675                                           ssh_rportfwd_succfail, pf);\r
4676                     } else {\r
4677                         struct Packet *pktout;\r
4678                         pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
4679                         ssh2_pkt_addstring(pktout, "tcpip-forward");\r
4680                         ssh2_pkt_addbool(pktout, 1);/* want reply */\r
4681                         if (epf->saddr) {\r
4682                             ssh2_pkt_addstring(pktout, epf->saddr);\r
4683                         } else if (cfg->rport_acceptall) {\r
4684                             ssh2_pkt_addstring(pktout, "0.0.0.0");\r
4685                         } else {\r
4686                             ssh2_pkt_addstring(pktout, "127.0.0.1");\r
4687                         }\r
4688                         ssh2_pkt_adduint32(pktout, epf->sport);\r
4689                         ssh2_pkt_send(ssh, pktout);\r
4691                         ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,\r
4692                                           SSH2_MSG_REQUEST_FAILURE,\r
4693                                           ssh_rportfwd_succfail, pf);\r
4694                     }\r
4695                 }\r
4696             }\r
4697             sfree(sportdesc);\r
4698             sfree(dportdesc);\r
4699         }\r
4702 static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin)\r
4704     char *string;\r
4705     int stringlen, bufsize;\r
4707     ssh_pkt_getstring(pktin, &string, &stringlen);\r
4708     if (string == NULL) {\r
4709         bombout(("Incoming terminal data packet was badly formed"));\r
4710         return;\r
4711     }\r
4713     bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA,\r
4714                            string, stringlen);\r
4715     if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {\r
4716         ssh->v1_stdout_throttling = 1;\r
4717         ssh_throttle_conn(ssh, +1);\r
4718     }\r
4721 static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)\r
4723     /* Remote side is trying to open a channel to talk to our\r
4724      * X-Server. Give them back a local channel number. */\r
4725     struct ssh_channel *c;\r
4726     int remoteid = ssh_pkt_getuint32(pktin);\r
4728     logevent("Received X11 connect request");\r
4729     /* Refuse if X11 forwarding is disabled. */\r
4730     if (!ssh->X11_fwd_enabled) {\r
4731         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4732                     PKT_INT, remoteid, PKT_END);\r
4733         logevent("Rejected X11 connect request");\r
4734     } else {\r
4735         c = snew(struct ssh_channel);\r
4736         c->ssh = ssh;\r
4738         if (x11_init(&c->u.x11.s, ssh->x11disp, c,\r
4739                      NULL, -1, &ssh->cfg) != NULL) {\r
4740             logevent("Opening X11 forward connection failed");\r
4741             sfree(c);\r
4742             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4743                         PKT_INT, remoteid, PKT_END);\r
4744         } else {\r
4745             logevent\r
4746                 ("Opening X11 forward connection succeeded");\r
4747             c->remoteid = remoteid;\r
4748             c->halfopen = FALSE;\r
4749             c->localid = alloc_channel_id(ssh);\r
4750             c->closes = 0;\r
4751             c->pending_close = FALSE;\r
4752             c->throttling_conn = 0;\r
4753             c->type = CHAN_X11; /* identify channel type */\r
4754             add234(ssh->channels, c);\r
4755             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4756                         PKT_INT, c->remoteid, PKT_INT,\r
4757                         c->localid, PKT_END);\r
4758             logevent("Opened X11 forward channel");\r
4759         }\r
4760     }\r
4763 static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)\r
4765     /* Remote side is trying to open a channel to talk to our\r
4766      * agent. Give them back a local channel number. */\r
4767     struct ssh_channel *c;\r
4768     int remoteid = ssh_pkt_getuint32(pktin);\r
4770     /* Refuse if agent forwarding is disabled. */\r
4771     if (!ssh->agentfwd_enabled) {\r
4772         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4773                     PKT_INT, remoteid, PKT_END);\r
4774     } else {\r
4775         c = snew(struct ssh_channel);\r
4776         c->ssh = ssh;\r
4777         c->remoteid = remoteid;\r
4778         c->halfopen = FALSE;\r
4779         c->localid = alloc_channel_id(ssh);\r
4780         c->closes = 0;\r
4781         c->pending_close = FALSE;\r
4782         c->throttling_conn = 0;\r
4783         c->type = CHAN_AGENT;   /* identify channel type */\r
4784         c->u.a.lensofar = 0;\r
4785         add234(ssh->channels, c);\r
4786         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4787                     PKT_INT, c->remoteid, PKT_INT, c->localid,\r
4788                     PKT_END);\r
4789     }\r
4792 static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)\r
4794     /* Remote side is trying to open a channel to talk to a\r
4795      * forwarded port. Give them back a local channel number. */\r
4796     struct ssh_channel *c;\r
4797     struct ssh_rportfwd pf, *pfp;\r
4798     int remoteid;\r
4799     int hostsize, port;\r
4800     char *host;\r
4801     const char *e;\r
4802     c = snew(struct ssh_channel);\r
4803     c->ssh = ssh;\r
4805     remoteid = ssh_pkt_getuint32(pktin);\r
4806     ssh_pkt_getstring(pktin, &host, &hostsize);\r
4807     port = ssh_pkt_getuint32(pktin);\r
4809     if (hostsize >= lenof(pf.dhost))\r
4810         hostsize = lenof(pf.dhost)-1;\r
4811     memcpy(pf.dhost, host, hostsize);\r
4812     pf.dhost[hostsize] = '\0';\r
4813     pf.dport = port;\r
4814     pfp = find234(ssh->rportfwds, &pf, NULL);\r
4816     if (pfp == NULL) {\r
4817         logeventf(ssh, "Rejected remote port open request for %s:%d",\r
4818                   pf.dhost, port);\r
4819         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4820                     PKT_INT, remoteid, PKT_END);\r
4821     } else {\r
4822         logeventf(ssh, "Received remote port open request for %s:%d",\r
4823                   pf.dhost, port);\r
4824         e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,\r
4825                            c, &ssh->cfg, pfp->pfrec->addressfamily);\r
4826         if (e != NULL) {\r
4827             logeventf(ssh, "Port open failed: %s", e);\r
4828             sfree(c);\r
4829             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
4830                         PKT_INT, remoteid, PKT_END);\r
4831         } else {\r
4832             c->remoteid = remoteid;\r
4833             c->halfopen = FALSE;\r
4834             c->localid = alloc_channel_id(ssh);\r
4835             c->closes = 0;\r
4836             c->pending_close = FALSE;\r
4837             c->throttling_conn = 0;\r
4838             c->type = CHAN_SOCKDATA;    /* identify channel type */\r
4839             add234(ssh->channels, c);\r
4840             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
4841                         PKT_INT, c->remoteid, PKT_INT,\r
4842                         c->localid, PKT_END);\r
4843             logevent("Forwarded port opened successfully");\r
4844         }\r
4845     }\r
4848 static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
4850     unsigned int remoteid = ssh_pkt_getuint32(pktin);\r
4851     unsigned int localid = ssh_pkt_getuint32(pktin);\r
4852     struct ssh_channel *c;\r
4854     c = find234(ssh->channels, &remoteid, ssh_channelfind);\r
4855     if (c && c->type == CHAN_SOCKDATA_DORMANT) {\r
4856         c->remoteid = localid;\r
4857         c->halfopen = FALSE;\r
4858         c->type = CHAN_SOCKDATA;\r
4859         c->throttling_conn = 0;\r
4860         pfd_confirm(c->u.pfd.s);\r
4861     }\r
4863     if (c && c->closes) {\r
4864         /*\r
4865          * We have a pending close on this channel,\r
4866          * which we decided on before the server acked\r
4867          * the channel open. So now we know the\r
4868          * remoteid, we can close it again.\r
4869          */\r
4870         send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE,\r
4871                     PKT_INT, c->remoteid, PKT_END);\r
4872     }\r
4875 static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
4877     unsigned int remoteid = ssh_pkt_getuint32(pktin);\r
4878     struct ssh_channel *c;\r
4880     c = find234(ssh->channels, &remoteid, ssh_channelfind);\r
4881     if (c && c->type == CHAN_SOCKDATA_DORMANT) {\r
4882         logevent("Forwarded connection refused by server");\r
4883         pfd_close(c->u.pfd.s);\r
4884         del234(ssh->channels, c);\r
4885         sfree(c);\r
4886     }\r
4889 static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
4891     /* Remote side closes a channel. */\r
4892     unsigned i = ssh_pkt_getuint32(pktin);\r
4893     struct ssh_channel *c;\r
4894     c = find234(ssh->channels, &i, ssh_channelfind);\r
4895     if (c && !c->halfopen) {\r
4896         int closetype;\r
4897         closetype =\r
4898             (pktin->type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);\r
4900         if ((c->closes == 0) && (c->type == CHAN_X11)) {\r
4901             logevent("Forwarded X11 connection terminated");\r
4902             assert(c->u.x11.s != NULL);\r
4903             x11_close(c->u.x11.s);\r
4904             c->u.x11.s = NULL;\r
4905         }\r
4906         if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) {\r
4907             logevent("Forwarded port closed");\r
4908             assert(c->u.pfd.s != NULL);\r
4909             pfd_close(c->u.pfd.s);\r
4910             c->u.pfd.s = NULL;\r
4911         }\r
4913         c->closes |= (closetype << 2);   /* seen this message */\r
4914         if (!(c->closes & closetype)) {\r
4915             send_packet(ssh, pktin->type, PKT_INT, c->remoteid,\r
4916                         PKT_END);\r
4917             c->closes |= closetype;      /* sent it too */\r
4918         }\r
4920         if (c->closes == 15) {\r
4921             del234(ssh->channels, c);\r
4922             sfree(c);\r
4923         }\r
4924     } else {\r
4925         bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",\r
4926                  pktin->type == SSH1_MSG_CHANNEL_CLOSE ? "" :\r
4927                  "_CONFIRMATION", c ? "half-open" : "nonexistent",\r
4928                  i));\r
4929     }\r
4932 static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
4934     /* Data sent down one of our channels. */\r
4935     int i = ssh_pkt_getuint32(pktin);\r
4936     char *p;\r
4937     int len;\r
4938     struct ssh_channel *c;\r
4940     ssh_pkt_getstring(pktin, &p, &len);\r
4942     c = find234(ssh->channels, &i, ssh_channelfind);\r
4943     if (c) {\r
4944         int bufsize = 0;\r
4945         switch (c->type) {\r
4946           case CHAN_X11:\r
4947             bufsize = x11_send(c->u.x11.s, p, len);\r
4948             break;\r
4949           case CHAN_SOCKDATA:\r
4950             bufsize = pfd_send(c->u.pfd.s, p, len);\r
4951             break;\r
4952           case CHAN_AGENT:\r
4953             /* Data for an agent message. Buffer it. */\r
4954             while (len > 0) {\r
4955                 if (c->u.a.lensofar < 4) {\r
4956                     unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len);\r
4957                     memcpy(c->u.a.msglen + c->u.a.lensofar, p,\r
4958                            l);\r
4959                     p += l;\r
4960                     len -= l;\r
4961                     c->u.a.lensofar += l;\r
4962                 }\r
4963                 if (c->u.a.lensofar == 4) {\r
4964                     c->u.a.totallen =\r
4965                         4 + GET_32BIT(c->u.a.msglen);\r
4966                     c->u.a.message = snewn(c->u.a.totallen,\r
4967                                            unsigned char);\r
4968                     memcpy(c->u.a.message, c->u.a.msglen, 4);\r
4969                 }\r
4970                 if (c->u.a.lensofar >= 4 && len > 0) {\r
4971                     unsigned int l =\r
4972                         min(c->u.a.totallen - c->u.a.lensofar,\r
4973                             (unsigned)len);\r
4974                     memcpy(c->u.a.message + c->u.a.lensofar, p,\r
4975                            l);\r
4976                     p += l;\r
4977                     len -= l;\r
4978                     c->u.a.lensofar += l;\r
4979                 }\r
4980                 if (c->u.a.lensofar == c->u.a.totallen) {\r
4981                     void *reply;\r
4982                     int replylen;\r
4983                     if (agent_query(c->u.a.message,\r
4984                                     c->u.a.totallen,\r
4985                                     &reply, &replylen,\r
4986                                     ssh_agentf_callback, c))\r
4987                         ssh_agentf_callback(c, reply, replylen);\r
4988                     sfree(c->u.a.message);\r
4989                     c->u.a.lensofar = 0;\r
4990                 }\r
4991             }\r
4992             bufsize = 0;   /* agent channels never back up */\r
4993             break;\r
4994         }\r
4995         if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {\r
4996             c->throttling_conn = 1;\r
4997             ssh_throttle_conn(ssh, +1);\r
4998         }\r
4999     }\r
5002 static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin)\r
5004     ssh->exitcode = ssh_pkt_getuint32(pktin);\r
5005     logeventf(ssh, "Server sent command exit status %d", ssh->exitcode);\r
5006     send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);\r
5007     /*\r
5008      * In case `helpful' firewalls or proxies tack\r
5009      * extra human-readable text on the end of the\r
5010      * session which we might mistake for another\r
5011      * encrypted packet, we close the session once\r
5012      * we've sent EXIT_CONFIRMATION.\r
5013      */\r
5014     ssh_disconnect(ssh, NULL, NULL, 0, TRUE);\r
5017 /* Helper function to deal with sending tty modes for REQUEST_PTY */\r
5018 static void ssh1_send_ttymode(void *data, char *mode, char *val)\r
5020     struct Packet *pktout = (struct Packet *)data;\r
5021     int i = 0;\r
5022     unsigned int arg = 0;\r
5023     while (strcmp(mode, ssh_ttymodes[i].mode) != 0) i++;\r
5024     if (i == lenof(ssh_ttymodes)) return;\r
5025     switch (ssh_ttymodes[i].type) {\r
5026       case TTY_OP_CHAR:\r
5027         arg = ssh_tty_parse_specchar(val);\r
5028         break;\r
5029       case TTY_OP_BOOL:\r
5030         arg = ssh_tty_parse_boolean(val);\r
5031         break;\r
5032     }\r
5033     ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode);\r
5034     ssh2_pkt_addbyte(pktout, arg);\r
5038 static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen,\r
5039                                struct Packet *pktin)\r
5041     crBegin(ssh->do_ssh1_connection_crstate);\r
5043     ssh->packet_dispatch[SSH1_SMSG_STDOUT_DATA] = \r
5044         ssh->packet_dispatch[SSH1_SMSG_STDERR_DATA] =\r
5045         ssh1_smsg_stdout_stderr_data;\r
5047     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
5048         ssh1_msg_channel_open_confirmation;\r
5049     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_FAILURE] =\r
5050         ssh1_msg_channel_open_failure;\r
5051     ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE] =\r
5052         ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION] =\r
5053         ssh1_msg_channel_close;\r
5054     ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data;\r
5055     ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status;\r
5057     if (ssh->cfg.agentfwd && agent_exists()) {\r
5058         logevent("Requesting agent forwarding");\r
5059         send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);\r
5060         do {\r
5061             crReturnV;\r
5062         } while (!pktin);\r
5063         if (pktin->type != SSH1_SMSG_SUCCESS\r
5064             && pktin->type != SSH1_SMSG_FAILURE) {\r
5065             bombout(("Protocol confusion"));\r
5066             crStopV;\r
5067         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5068             logevent("Agent forwarding refused");\r
5069         } else {\r
5070             logevent("Agent forwarding enabled");\r
5071             ssh->agentfwd_enabled = TRUE;\r
5072             ssh->packet_dispatch[SSH1_SMSG_AGENT_OPEN] = ssh1_smsg_agent_open;\r
5073         }\r
5074     }\r
5076     if (ssh->cfg.x11_forward &&\r
5077         (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,\r
5078                                           ssh->cfg.x11_auth, &ssh->cfg))) {\r
5079         logevent("Requesting X11 forwarding");\r
5080         /*\r
5081          * Note that while we blank the X authentication data here, we don't\r
5082          * take any special action to blank the start of an X11 channel,\r
5083          * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection\r
5084          * without having session blanking enabled is likely to leak your\r
5085          * cookie into the log.\r
5086          */\r
5087         if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {\r
5088             send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5089                         PKT_STR, ssh->x11disp->remoteauthprotoname,\r
5090                         PKTT_PASSWORD,\r
5091                         PKT_STR, ssh->x11disp->remoteauthdatastring,\r
5092                         PKTT_OTHER,\r
5093                         PKT_INT, ssh->x11disp->screennum,\r
5094                         PKT_END);\r
5095         } else {\r
5096             send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5097                         PKT_STR, ssh->x11disp->remoteauthprotoname,\r
5098                         PKTT_PASSWORD,\r
5099                         PKT_STR, ssh->x11disp->remoteauthdatastring,\r
5100                         PKTT_OTHER,\r
5101                         PKT_END);\r
5102         }\r
5103         do {\r
5104             crReturnV;\r
5105         } while (!pktin);\r
5106         if (pktin->type != SSH1_SMSG_SUCCESS\r
5107             && pktin->type != SSH1_SMSG_FAILURE) {\r
5108             bombout(("Protocol confusion"));\r
5109             crStopV;\r
5110         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5111             logevent("X11 forwarding refused");\r
5112         } else {\r
5113             logevent("X11 forwarding enabled");\r
5114             ssh->X11_fwd_enabled = TRUE;\r
5115             ssh->packet_dispatch[SSH1_SMSG_X11_OPEN] = ssh1_smsg_x11_open;\r
5116         }\r
5117     }\r
5119     ssh_setup_portfwd(ssh, &ssh->cfg);\r
5120     ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open;\r
5122     if (!ssh->cfg.nopty) {\r
5123         struct Packet *pkt;\r
5124         /* Unpick the terminal-speed string. */\r
5125         /* XXX perhaps we should allow no speeds to be sent. */\r
5126         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
5127         sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
5128         /* Send the pty request. */\r
5129         pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY);\r
5130         ssh_pkt_addstring(pkt, ssh->cfg.termtype);\r
5131         ssh_pkt_adduint32(pkt, ssh->term_height);\r
5132         ssh_pkt_adduint32(pkt, ssh->term_width);\r
5133         ssh_pkt_adduint32(pkt, 0); /* width in pixels */\r
5134         ssh_pkt_adduint32(pkt, 0); /* height in pixels */\r
5135         parse_ttymodes(ssh, ssh->cfg.ttymodes,\r
5136                        ssh1_send_ttymode, (void *)pkt);\r
5137         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_ISPEED);\r
5138         ssh_pkt_adduint32(pkt, ssh->ispeed);\r
5139         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_OSPEED);\r
5140         ssh_pkt_adduint32(pkt, ssh->ospeed);\r
5141         ssh_pkt_addbyte(pkt, SSH_TTY_OP_END);\r
5142         s_wrpkt(ssh, pkt);\r
5143         ssh->state = SSH_STATE_INTERMED;\r
5144         do {\r
5145             crReturnV;\r
5146         } while (!pktin);\r
5147         if (pktin->type != SSH1_SMSG_SUCCESS\r
5148             && pktin->type != SSH1_SMSG_FAILURE) {\r
5149             bombout(("Protocol confusion"));\r
5150             crStopV;\r
5151         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5152             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
5153             ssh->editing = ssh->echoing = 1;\r
5154         }\r
5155         logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
5156                   ssh->ospeed, ssh->ispeed);\r
5157     } else {\r
5158         ssh->editing = ssh->echoing = 1;\r
5159     }\r
5161     if (ssh->cfg.compression) {\r
5162         send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);\r
5163         do {\r
5164             crReturnV;\r
5165         } while (!pktin);\r
5166         if (pktin->type != SSH1_SMSG_SUCCESS\r
5167             && pktin->type != SSH1_SMSG_FAILURE) {\r
5168             bombout(("Protocol confusion"));\r
5169             crStopV;\r
5170         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5171             c_write_str(ssh, "Server refused to compress\r\n");\r
5172         }\r
5173         logevent("Started compression");\r
5174         ssh->v1_compressing = TRUE;\r
5175         ssh->cs_comp_ctx = zlib_compress_init();\r
5176         logevent("Initialised zlib (RFC1950) compression");\r
5177         ssh->sc_comp_ctx = zlib_decompress_init();\r
5178         logevent("Initialised zlib (RFC1950) decompression");\r
5179     }\r
5181     /*\r
5182      * Start the shell or command.\r
5183      * \r
5184      * Special case: if the first-choice command is an SSH-2\r
5185      * subsystem (hence not usable here) and the second choice\r
5186      * exists, we fall straight back to that.\r
5187      */\r
5188     {\r
5189         char *cmd = ssh->cfg.remote_cmd_ptr;\r
5191         if (!cmd) cmd = ssh->cfg.remote_cmd;\r
5192         \r
5193         if (ssh->cfg.ssh_subsys && ssh->cfg.remote_cmd_ptr2) {\r
5194             cmd = ssh->cfg.remote_cmd_ptr2;\r
5195             ssh->fallback_cmd = TRUE;\r
5196         }\r
5197         if (*cmd)\r
5198             send_packet(ssh, SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);\r
5199         else\r
5200             send_packet(ssh, SSH1_CMSG_EXEC_SHELL, PKT_END);\r
5201         logevent("Started session");\r
5202     }\r
5204     ssh->state = SSH_STATE_SESSION;\r
5205     if (ssh->size_needed)\r
5206         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
5207     if (ssh->eof_needed)\r
5208         ssh_special(ssh, TS_EOF);\r
5210     if (ssh->ldisc)\r
5211         ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */\r
5212     ssh->send_ok = 1;\r
5213     ssh->channels = newtree234(ssh_channelcmp);\r
5214     while (1) {\r
5216         /*\r
5217          * By this point, most incoming packets are already being\r
5218          * handled by the dispatch table, and we need only pay\r
5219          * attention to the unusual ones.\r
5220          */\r
5222         crReturnV;\r
5223         if (pktin) {\r
5224             if (pktin->type == SSH1_SMSG_SUCCESS) {\r
5225                 /* may be from EXEC_SHELL on some servers */\r
5226             } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5227                 /* may be from EXEC_SHELL on some servers\r
5228                  * if no pty is available or in other odd cases. Ignore */\r
5229             } else {\r
5230                 bombout(("Strange packet received: type %d", pktin->type));\r
5231                 crStopV;\r
5232             }\r
5233         } else {\r
5234             while (inlen > 0) {\r
5235                 int len = min(inlen, 512);\r
5236                 send_packet(ssh, SSH1_CMSG_STDIN_DATA,\r
5237                             PKT_INT, len,  PKTT_DATA, PKT_DATA, in, len,\r
5238                             PKTT_OTHER, PKT_END);\r
5239                 in += len;\r
5240                 inlen -= len;\r
5241             }\r
5242         }\r
5243     }\r
5245     crFinishV;\r
5248 /*\r
5249  * Handle the top-level SSH-2 protocol.\r
5250  */\r
5251 static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin)\r
5253     char *msg;\r
5254     int msglen;\r
5256     ssh_pkt_getstring(pktin, &msg, &msglen);\r
5257     logeventf(ssh, "Remote debug message: %.*s", msglen, msg);\r
5260 static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
5262     /* log reason code in disconnect message */\r
5263     char *msg;\r
5264     int msglen;\r
5266     ssh_pkt_getstring(pktin, &msg, &msglen);\r
5267     bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));\r
5270 static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)\r
5272     /* Do nothing, because we're ignoring it! Duhh. */\r
5275 static void ssh1_protocol_setup(Ssh ssh)\r
5277     int i;\r
5279     /*\r
5280      * Most messages are handled by the coroutines.\r
5281      */\r
5282     for (i = 0; i < 256; i++)\r
5283         ssh->packet_dispatch[i] = NULL;\r
5285     /*\r
5286      * These special message types we install handlers for.\r
5287      */\r
5288     ssh->packet_dispatch[SSH1_MSG_DISCONNECT] = ssh1_msg_disconnect;\r
5289     ssh->packet_dispatch[SSH1_MSG_IGNORE] = ssh_msg_ignore;\r
5290     ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug;\r
5293 static void ssh1_protocol(Ssh ssh, void *vin, int inlen,\r
5294                           struct Packet *pktin)\r
5296     unsigned char *in=(unsigned char*)vin;\r
5297     if (ssh->state == SSH_STATE_CLOSED)\r
5298         return;\r
5300     if (pktin && ssh->packet_dispatch[pktin->type]) {\r
5301         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
5302         return;\r
5303     }\r
5305     if (!ssh->protocol_initial_phase_done) {\r
5306         if (do_ssh1_login(ssh, in, inlen, pktin))\r
5307             ssh->protocol_initial_phase_done = TRUE;\r
5308         else\r
5309             return;\r
5310     }\r
5312     do_ssh1_connection(ssh, in, inlen, pktin);\r
5315 /*\r
5316  * Utility routine for decoding comma-separated strings in KEXINIT.\r
5317  */\r
5318 static int in_commasep_string(char *needle, char *haystack, int haylen)\r
5320     int needlen;\r
5321     if (!needle || !haystack)          /* protect against null pointers */\r
5322         return 0;\r
5323     needlen = strlen(needle);\r
5324     while (1) {\r
5325         /*\r
5326          * Is it at the start of the string?\r
5327          */\r
5328         if (haylen >= needlen &&       /* haystack is long enough */\r
5329             !memcmp(needle, haystack, needlen) &&       /* initial match */\r
5330             (haylen == needlen || haystack[needlen] == ',')\r
5331             /* either , or EOS follows */\r
5332             )\r
5333             return 1;\r
5334         /*\r
5335          * If not, search for the next comma and resume after that.\r
5336          * If no comma found, terminate.\r
5337          */\r
5338         while (haylen > 0 && *haystack != ',')\r
5339             haylen--, haystack++;\r
5340         if (haylen == 0)\r
5341             return 0;\r
5342         haylen--, haystack++;          /* skip over comma itself */\r
5343     }\r
5346 /*\r
5347  * Similar routine for checking whether we have the first string in a list.\r
5348  */\r
5349 static int first_in_commasep_string(char *needle, char *haystack, int haylen)\r
5351     int needlen;\r
5352     if (!needle || !haystack)          /* protect against null pointers */\r
5353         return 0;\r
5354     needlen = strlen(needle);\r
5355     /*\r
5356      * Is it at the start of the string?\r
5357      */\r
5358     if (haylen >= needlen &&       /* haystack is long enough */\r
5359         !memcmp(needle, haystack, needlen) &&   /* initial match */\r
5360         (haylen == needlen || haystack[needlen] == ',')\r
5361         /* either , or EOS follows */\r
5362         )\r
5363         return 1;\r
5364     return 0;\r
5368 /*\r
5369  * SSH-2 key creation method.\r
5370  * (Currently assumes 2 lots of any hash are sufficient to generate\r
5371  * keys/IVs for any cipher/MAC. SSH2_MKKEY_ITERS documents this assumption.)\r
5372  */\r
5373 #define SSH2_MKKEY_ITERS (2)\r
5374 static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr,\r
5375                        unsigned char *keyspace)\r
5377     const struct ssh_hash *h = ssh->kex->hash;\r
5378     void *s;\r
5379     /* First hlen bytes. */\r
5380     s = h->init();\r
5381     if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
5382         hash_mpint(h, s, K);\r
5383     h->bytes(s, H, h->hlen);\r
5384     h->bytes(s, &chr, 1);\r
5385     h->bytes(s, ssh->v2_session_id, ssh->v2_session_id_len);\r
5386     h->final(s, keyspace);\r
5387     /* Next hlen bytes. */\r
5388     s = h->init();\r
5389     if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
5390         hash_mpint(h, s, K);\r
5391     h->bytes(s, H, h->hlen);\r
5392     h->bytes(s, keyspace, h->hlen);\r
5393     h->final(s, keyspace + h->hlen);\r
5396 /*\r
5397  * Handle the SSH-2 transport layer.\r
5398  */\r
5399 static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,\r
5400                              struct Packet *pktin)\r
5402     unsigned char *in = (unsigned char *)vin;\r
5403     struct do_ssh2_transport_state {\r
5404         int nbits, pbits, warn_kex, warn_cscipher, warn_sccipher;\r
5405         Bignum p, g, e, f, K;\r
5406         void *our_kexinit;\r
5407         int our_kexinitlen;\r
5408         int kex_init_value, kex_reply_value;\r
5409         const struct ssh_mac **maclist;\r
5410         int nmacs;\r
5411         const struct ssh2_cipher *cscipher_tobe;\r
5412         const struct ssh2_cipher *sccipher_tobe;\r
5413         const struct ssh_mac *csmac_tobe;\r
5414         const struct ssh_mac *scmac_tobe;\r
5415         const struct ssh_compress *cscomp_tobe;\r
5416         const struct ssh_compress *sccomp_tobe;\r
5417         char *hostkeydata, *sigdata, *rsakeydata, *keystr, *fingerprint;\r
5418         int hostkeylen, siglen, rsakeylen;\r
5419         void *hkey;                    /* actual host key */\r
5420         void *rsakey;                  /* for RSA kex */\r
5421         unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN];\r
5422         int n_preferred_kex;\r
5423         const struct ssh_kexes *preferred_kex[KEX_MAX];\r
5424         int n_preferred_ciphers;\r
5425         const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];\r
5426         const struct ssh_compress *preferred_comp;\r
5427         int userauth_succeeded;     /* for delayed compression */\r
5428         int pending_compression;\r
5429         int got_session_id, activated_authconn;\r
5430         struct Packet *pktout;\r
5431         int dlgret;\r
5432         int guessok;\r
5433         int ignorepkt;\r
5434     };\r
5435     crState(do_ssh2_transport_state);\r
5437     crBegin(ssh->do_ssh2_transport_crstate);\r
5439     s->cscipher_tobe = s->sccipher_tobe = NULL;\r
5440     s->csmac_tobe = s->scmac_tobe = NULL;\r
5441     s->cscomp_tobe = s->sccomp_tobe = NULL;\r
5443     s->got_session_id = s->activated_authconn = FALSE;\r
5444     s->userauth_succeeded = FALSE;\r
5445     s->pending_compression = FALSE;\r
5447     /*\r
5448      * Be prepared to work around the buggy MAC problem.\r
5449      */\r
5450     if (ssh->remote_bugs & BUG_SSH2_HMAC)\r
5451         s->maclist = buggymacs, s->nmacs = lenof(buggymacs);\r
5452     else\r
5453         s->maclist = macs, s->nmacs = lenof(macs);\r
5455   begin_key_exchange:\r
5456     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
5457     {\r
5458         int i, j, commalist_started;\r
5460         /*\r
5461          * Set up the preferred key exchange. (NULL => warn below here)\r
5462          */\r
5463         s->n_preferred_kex = 0;\r
5464         for (i = 0; i < KEX_MAX; i++) {\r
5465             switch (ssh->cfg.ssh_kexlist[i]) {\r
5466               case KEX_DHGEX:\r
5467                 s->preferred_kex[s->n_preferred_kex++] =\r
5468                     &ssh_diffiehellman_gex;\r
5469                 break;\r
5470               case KEX_DHGROUP14:\r
5471                 s->preferred_kex[s->n_preferred_kex++] =\r
5472                     &ssh_diffiehellman_group14;\r
5473                 break;\r
5474               case KEX_DHGROUP1:\r
5475                 s->preferred_kex[s->n_preferred_kex++] =\r
5476                     &ssh_diffiehellman_group1;\r
5477                 break;\r
5478               case KEX_RSA:\r
5479                 s->preferred_kex[s->n_preferred_kex++] =\r
5480                     &ssh_rsa_kex;\r
5481                 break;\r
5482               case KEX_WARN:\r
5483                 /* Flag for later. Don't bother if it's the last in\r
5484                  * the list. */\r
5485                 if (i < KEX_MAX - 1) {\r
5486                     s->preferred_kex[s->n_preferred_kex++] = NULL;\r
5487                 }\r
5488                 break;\r
5489             }\r
5490         }\r
5492         /*\r
5493          * Set up the preferred ciphers. (NULL => warn below here)\r
5494          */\r
5495         s->n_preferred_ciphers = 0;\r
5496         for (i = 0; i < CIPHER_MAX; i++) {\r
5497             switch (ssh->cfg.ssh_cipherlist[i]) {\r
5498               case CIPHER_BLOWFISH:\r
5499                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish;\r
5500                 break;\r
5501               case CIPHER_DES:\r
5502                 if (ssh->cfg.ssh2_des_cbc) {\r
5503                     s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des;\r
5504                 }\r
5505                 break;\r
5506               case CIPHER_3DES:\r
5507                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des;\r
5508                 break;\r
5509               case CIPHER_AES:\r
5510                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes;\r
5511                 break;\r
5512               case CIPHER_ARCFOUR:\r
5513                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour;\r
5514                 break;\r
5515               case CIPHER_WARN:\r
5516                 /* Flag for later. Don't bother if it's the last in\r
5517                  * the list. */\r
5518                 if (i < CIPHER_MAX - 1) {\r
5519                     s->preferred_ciphers[s->n_preferred_ciphers++] = NULL;\r
5520                 }\r
5521                 break;\r
5522             }\r
5523         }\r
5525         /*\r
5526          * Set up preferred compression.\r
5527          */\r
5528         if (ssh->cfg.compression)\r
5529             s->preferred_comp = &ssh_zlib;\r
5530         else\r
5531             s->preferred_comp = &ssh_comp_none;\r
5533         /*\r
5534          * Enable queueing of outgoing auth- or connection-layer\r
5535          * packets while we are in the middle of a key exchange.\r
5536          */\r
5537         ssh->queueing = TRUE;\r
5539         /*\r
5540          * Flag that KEX is in progress.\r
5541          */\r
5542         ssh->kex_in_progress = TRUE;\r
5544         /*\r
5545          * Construct and send our key exchange packet.\r
5546          */\r
5547         s->pktout = ssh2_pkt_init(SSH2_MSG_KEXINIT);\r
5548         for (i = 0; i < 16; i++)\r
5549             ssh2_pkt_addbyte(s->pktout, (unsigned char) random_byte());\r
5550         /* List key exchange algorithms. */\r
5551         ssh2_pkt_addstring_start(s->pktout);\r
5552         commalist_started = 0;\r
5553         for (i = 0; i < s->n_preferred_kex; i++) {\r
5554             const struct ssh_kexes *k = s->preferred_kex[i];\r
5555             if (!k) continue;          /* warning flag */\r
5556             for (j = 0; j < k->nkexes; j++) {\r
5557                 if (commalist_started)\r
5558                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5559                 ssh2_pkt_addstring_str(s->pktout, k->list[j]->name);\r
5560                 commalist_started = 1;\r
5561             }\r
5562         }\r
5563         /* List server host key algorithms. */\r
5564         ssh2_pkt_addstring_start(s->pktout);\r
5565         for (i = 0; i < lenof(hostkey_algs); i++) {\r
5566             ssh2_pkt_addstring_str(s->pktout, hostkey_algs[i]->name);\r
5567             if (i < lenof(hostkey_algs) - 1)\r
5568                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5569         }\r
5570         /* List client->server encryption algorithms. */\r
5571         ssh2_pkt_addstring_start(s->pktout);\r
5572         commalist_started = 0;\r
5573         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5574             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5575             if (!c) continue;          /* warning flag */\r
5576             for (j = 0; j < c->nciphers; j++) {\r
5577                 if (commalist_started)\r
5578                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5579                 ssh2_pkt_addstring_str(s->pktout, c->list[j]->name);\r
5580                 commalist_started = 1;\r
5581             }\r
5582         }\r
5583         /* List server->client encryption algorithms. */\r
5584         ssh2_pkt_addstring_start(s->pktout);\r
5585         commalist_started = 0;\r
5586         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5587             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5588             if (!c) continue; /* warning flag */\r
5589             for (j = 0; j < c->nciphers; j++) {\r
5590                 if (commalist_started)\r
5591                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5592                 ssh2_pkt_addstring_str(s->pktout, c->list[j]->name);\r
5593                 commalist_started = 1;\r
5594             }\r
5595         }\r
5596         /* List client->server MAC algorithms. */\r
5597         ssh2_pkt_addstring_start(s->pktout);\r
5598         for (i = 0; i < s->nmacs; i++) {\r
5599             ssh2_pkt_addstring_str(s->pktout, s->maclist[i]->name);\r
5600             if (i < s->nmacs - 1)\r
5601                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5602         }\r
5603         /* List server->client MAC algorithms. */\r
5604         ssh2_pkt_addstring_start(s->pktout);\r
5605         for (i = 0; i < s->nmacs; i++) {\r
5606             ssh2_pkt_addstring_str(s->pktout, s->maclist[i]->name);\r
5607             if (i < s->nmacs - 1)\r
5608                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5609         }\r
5610         /* List client->server compression algorithms,\r
5611          * then server->client compression algorithms. (We use the\r
5612          * same set twice.) */\r
5613         for (j = 0; j < 2; j++) {\r
5614             ssh2_pkt_addstring_start(s->pktout);\r
5615             assert(lenof(compressions) > 1);\r
5616             /* Prefer non-delayed versions */\r
5617             ssh2_pkt_addstring_str(s->pktout, s->preferred_comp->name);\r
5618             /* We don't even list delayed versions of algorithms until\r
5619              * they're allowed to be used, to avoid a race. See the end of\r
5620              * this function. */\r
5621             if (s->userauth_succeeded && s->preferred_comp->delayed_name) {\r
5622                 ssh2_pkt_addstring_str(s->pktout, ",");\r
5623                 ssh2_pkt_addstring_str(s->pktout,\r
5624                                        s->preferred_comp->delayed_name);\r
5625             }\r
5626             for (i = 0; i < lenof(compressions); i++) {\r
5627                 const struct ssh_compress *c = compressions[i];\r
5628                 if (c != s->preferred_comp) {\r
5629                     ssh2_pkt_addstring_str(s->pktout, ",");\r
5630                     ssh2_pkt_addstring_str(s->pktout, c->name);\r
5631                     if (s->userauth_succeeded && c->delayed_name) {\r
5632                         ssh2_pkt_addstring_str(s->pktout, ",");\r
5633                         ssh2_pkt_addstring_str(s->pktout, c->delayed_name);\r
5634                     }\r
5635                 }\r
5636             }\r
5637         }\r
5638         /* List client->server languages. Empty list. */\r
5639         ssh2_pkt_addstring_start(s->pktout);\r
5640         /* List server->client languages. Empty list. */\r
5641         ssh2_pkt_addstring_start(s->pktout);\r
5642         /* First KEX packet does _not_ follow, because we're not that brave. */\r
5643         ssh2_pkt_addbool(s->pktout, FALSE);\r
5644         /* Reserved. */\r
5645         ssh2_pkt_adduint32(s->pktout, 0);\r
5646     }\r
5648     s->our_kexinitlen = s->pktout->length - 5;\r
5649     s->our_kexinit = snewn(s->our_kexinitlen, unsigned char);\r
5650     memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); \r
5652     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
5654     if (!pktin)\r
5655         crWaitUntil(pktin);\r
5657     /*\r
5658      * Now examine the other side's KEXINIT to see what we're up\r
5659      * to.\r
5660      */\r
5661     {\r
5662         char *str, *preferred;\r
5663         int i, j, len;\r
5665         if (pktin->type != SSH2_MSG_KEXINIT) {\r
5666             bombout(("expected key exchange packet from server"));\r
5667             crStop(0);\r
5668         }\r
5669         ssh->kex = NULL;\r
5670         ssh->hostkey = NULL;\r
5671         s->cscipher_tobe = NULL;\r
5672         s->sccipher_tobe = NULL;\r
5673         s->csmac_tobe = NULL;\r
5674         s->scmac_tobe = NULL;\r
5675         s->cscomp_tobe = NULL;\r
5676         s->sccomp_tobe = NULL;\r
5677         s->warn_kex = s->warn_cscipher = s->warn_sccipher = FALSE;\r
5679         pktin->savedpos += 16;          /* skip garbage cookie */\r
5680         ssh_pkt_getstring(pktin, &str, &len);    /* key exchange algorithms */\r
5682         preferred = NULL;\r
5683         for (i = 0; i < s->n_preferred_kex; i++) {\r
5684             const struct ssh_kexes *k = s->preferred_kex[i];\r
5685             if (!k) {\r
5686                 s->warn_kex = TRUE;\r
5687             } else {\r
5688                 for (j = 0; j < k->nkexes; j++) {\r
5689                     if (!preferred) preferred = k->list[j]->name;\r
5690                     if (in_commasep_string(k->list[j]->name, str, len)) {\r
5691                         ssh->kex = k->list[j];\r
5692                         break;\r
5693                     }\r
5694                 }\r
5695             }\r
5696             if (ssh->kex)\r
5697                 break;\r
5698         }\r
5699         if (!ssh->kex) {\r
5700             bombout(("Couldn't agree a key exchange algorithm (available: %s)",\r
5701                      str ? str : "(null)"));\r
5702             crStop(0);\r
5703         }\r
5704         /*\r
5705          * Note that the server's guess is considered wrong if it doesn't match\r
5706          * the first algorithm in our list, even if it's still the algorithm\r
5707          * we end up using.\r
5708          */\r
5709         s->guessok = first_in_commasep_string(preferred, str, len);\r
5710         ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */\r
5711         for (i = 0; i < lenof(hostkey_algs); i++) {\r
5712             if (in_commasep_string(hostkey_algs[i]->name, str, len)) {\r
5713                 ssh->hostkey = hostkey_algs[i];\r
5714                 break;\r
5715             }\r
5716         }\r
5717         s->guessok = s->guessok &&\r
5718             first_in_commasep_string(hostkey_algs[0]->name, str, len);\r
5719         ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */\r
5720         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5721             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5722             if (!c) {\r
5723                 s->warn_cscipher = TRUE;\r
5724             } else {\r
5725                 for (j = 0; j < c->nciphers; j++) {\r
5726                     if (in_commasep_string(c->list[j]->name, str, len)) {\r
5727                         s->cscipher_tobe = c->list[j];\r
5728                         break;\r
5729                     }\r
5730                 }\r
5731             }\r
5732             if (s->cscipher_tobe)\r
5733                 break;\r
5734         }\r
5735         if (!s->cscipher_tobe) {\r
5736             bombout(("Couldn't agree a client-to-server cipher (available: %s)",\r
5737                      str ? str : "(null)"));\r
5738             crStop(0);\r
5739         }\r
5741         ssh_pkt_getstring(pktin, &str, &len);    /* server->client cipher */\r
5742         for (i = 0; i < s->n_preferred_ciphers; i++) {\r
5743             const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
5744             if (!c) {\r
5745                 s->warn_sccipher = TRUE;\r
5746             } else {\r
5747                 for (j = 0; j < c->nciphers; j++) {\r
5748                     if (in_commasep_string(c->list[j]->name, str, len)) {\r
5749                         s->sccipher_tobe = c->list[j];\r
5750                         break;\r
5751                     }\r
5752                 }\r
5753             }\r
5754             if (s->sccipher_tobe)\r
5755                 break;\r
5756         }\r
5757         if (!s->sccipher_tobe) {\r
5758             bombout(("Couldn't agree a server-to-client cipher (available: %s)",\r
5759                      str ? str : "(null)"));\r
5760             crStop(0);\r
5761         }\r
5763         ssh_pkt_getstring(pktin, &str, &len);    /* client->server mac */\r
5764         for (i = 0; i < s->nmacs; i++) {\r
5765             if (in_commasep_string(s->maclist[i]->name, str, len)) {\r
5766                 s->csmac_tobe = s->maclist[i];\r
5767                 break;\r
5768             }\r
5769         }\r
5770         ssh_pkt_getstring(pktin, &str, &len);    /* server->client mac */\r
5771         for (i = 0; i < s->nmacs; i++) {\r
5772             if (in_commasep_string(s->maclist[i]->name, str, len)) {\r
5773                 s->scmac_tobe = s->maclist[i];\r
5774                 break;\r
5775             }\r
5776         }\r
5777         ssh_pkt_getstring(pktin, &str, &len);  /* client->server compression */\r
5778         for (i = 0; i < lenof(compressions) + 1; i++) {\r
5779             const struct ssh_compress *c =\r
5780                 i == 0 ? s->preferred_comp : compressions[i - 1];\r
5781             if (in_commasep_string(c->name, str, len)) {\r
5782                 s->cscomp_tobe = c;\r
5783                 break;\r
5784             } else if (in_commasep_string(c->delayed_name, str, len)) {\r
5785                 if (s->userauth_succeeded) {\r
5786                     s->cscomp_tobe = c;\r
5787                     break;\r
5788                 } else {\r
5789                     s->pending_compression = TRUE;  /* try this later */\r
5790                 }\r
5791             }\r
5792         }\r
5793         ssh_pkt_getstring(pktin, &str, &len);  /* server->client compression */\r
5794         for (i = 0; i < lenof(compressions) + 1; i++) {\r
5795             const struct ssh_compress *c =\r
5796                 i == 0 ? s->preferred_comp : compressions[i - 1];\r
5797             if (in_commasep_string(c->name, str, len)) {\r
5798                 s->sccomp_tobe = c;\r
5799                 break;\r
5800             } else if (in_commasep_string(c->delayed_name, str, len)) {\r
5801                 if (s->userauth_succeeded) {\r
5802                     s->sccomp_tobe = c;\r
5803                     break;\r
5804                 } else {\r
5805                     s->pending_compression = TRUE;  /* try this later */\r
5806                 }\r
5807             }\r
5808         }\r
5809         if (s->pending_compression) {\r
5810             logevent("Server supports delayed compression; "\r
5811                      "will try this later");\r
5812         }\r
5813         ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */\r
5814         ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */\r
5815         s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok;\r
5817         if (s->warn_kex) {\r
5818             ssh_set_frozen(ssh, 1);\r
5819             s->dlgret = askalg(ssh->frontend, "key-exchange algorithm",\r
5820                                ssh->kex->name,\r
5821                                ssh_dialog_callback, ssh);\r
5822             if (s->dlgret < 0) {\r
5823                 do {\r
5824                     crReturn(0);\r
5825                     if (pktin) {\r
5826                         bombout(("Unexpected data from server while"\r
5827                                  " waiting for user response"));\r
5828                         crStop(0);\r
5829                     }\r
5830                 } while (pktin || inlen > 0);\r
5831                 s->dlgret = ssh->user_response;\r
5832             }\r
5833             ssh_set_frozen(ssh, 0);\r
5834             if (s->dlgret == 0) {\r
5835                 ssh_disconnect(ssh, "User aborted at kex warning", NULL,\r
5836                                0, TRUE);\r
5837                 crStop(0);\r
5838             }\r
5839         }\r
5841         if (s->warn_cscipher) {\r
5842             ssh_set_frozen(ssh, 1);\r
5843             s->dlgret = askalg(ssh->frontend,\r
5844                                "client-to-server cipher",\r
5845                                s->cscipher_tobe->name,\r
5846                                ssh_dialog_callback, ssh);\r
5847             if (s->dlgret < 0) {\r
5848                 do {\r
5849                     crReturn(0);\r
5850                     if (pktin) {\r
5851                         bombout(("Unexpected data from server while"\r
5852                                  " waiting for user response"));\r
5853                         crStop(0);\r
5854                     }\r
5855                 } while (pktin || inlen > 0);\r
5856                 s->dlgret = ssh->user_response;\r
5857             }\r
5858             ssh_set_frozen(ssh, 0);\r
5859             if (s->dlgret == 0) {\r
5860                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
5861                                0, TRUE);\r
5862                 crStop(0);\r
5863             }\r
5864         }\r
5866         if (s->warn_sccipher) {\r
5867             ssh_set_frozen(ssh, 1);\r
5868             s->dlgret = askalg(ssh->frontend,\r
5869                                "server-to-client cipher",\r
5870                                s->sccipher_tobe->name,\r
5871                                ssh_dialog_callback, ssh);\r
5872             if (s->dlgret < 0) {\r
5873                 do {\r
5874                     crReturn(0);\r
5875                     if (pktin) {\r
5876                         bombout(("Unexpected data from server while"\r
5877                                  " waiting for user response"));\r
5878                         crStop(0);\r
5879                     }\r
5880                 } while (pktin || inlen > 0);\r
5881                 s->dlgret = ssh->user_response;\r
5882             }\r
5883             ssh_set_frozen(ssh, 0);\r
5884             if (s->dlgret == 0) {\r
5885                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
5886                                0, TRUE);\r
5887                 crStop(0);\r
5888             }\r
5889         }\r
5891         ssh->exhash = ssh->kex->hash->init();\r
5892         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c));\r
5893         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s));\r
5894         hash_string(ssh->kex->hash, ssh->exhash,\r
5895             s->our_kexinit, s->our_kexinitlen);\r
5896         sfree(s->our_kexinit);\r
5897         if (pktin->length > 5)\r
5898             hash_string(ssh->kex->hash, ssh->exhash,\r
5899                 pktin->data + 5, pktin->length - 5);\r
5901         if (s->ignorepkt) /* first_kex_packet_follows */\r
5902             crWaitUntil(pktin);                /* Ignore packet */\r
5903     }\r
5905     if (ssh->kex->main_type == KEXTYPE_DH) {\r
5906         /*\r
5907          * Work out the number of bits of key we will need from the\r
5908          * key exchange. We start with the maximum key length of\r
5909          * either cipher...\r
5910          */\r
5911         {\r
5912             int csbits, scbits;\r
5914             csbits = s->cscipher_tobe->keylen;\r
5915             scbits = s->sccipher_tobe->keylen;\r
5916             s->nbits = (csbits > scbits ? csbits : scbits);\r
5917         }\r
5918         /* The keys only have hlen-bit entropy, since they're based on\r
5919          * a hash. So cap the key size at hlen bits. */\r
5920         if (s->nbits > ssh->kex->hash->hlen * 8)\r
5921             s->nbits = ssh->kex->hash->hlen * 8;\r
5923         /*\r
5924          * If we're doing Diffie-Hellman group exchange, start by\r
5925          * requesting a group.\r
5926          */\r
5927         if (!ssh->kex->pdata) {\r
5928             logevent("Doing Diffie-Hellman group exchange");\r
5929             ssh->pkt_kctx = SSH2_PKTCTX_DHGEX;\r
5930             /*\r
5931              * Work out how big a DH group we will need to allow that\r
5932              * much data.\r
5933              */\r
5934             s->pbits = 512 << ((s->nbits - 1) / 64);\r
5935             s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);\r
5936             ssh2_pkt_adduint32(s->pktout, s->pbits);\r
5937             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
5939             crWaitUntil(pktin);\r
5940             if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) {\r
5941                 bombout(("expected key exchange group packet from server"));\r
5942                 crStop(0);\r
5943             }\r
5944             s->p = ssh2_pkt_getmp(pktin);\r
5945             s->g = ssh2_pkt_getmp(pktin);\r
5946             if (!s->p || !s->g) {\r
5947                 bombout(("unable to read mp-ints from incoming group packet"));\r
5948                 crStop(0);\r
5949             }\r
5950             ssh->kex_ctx = dh_setup_gex(s->p, s->g);\r
5951             s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;\r
5952             s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;\r
5953         } else {\r
5954             ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP;\r
5955             ssh->kex_ctx = dh_setup_group(ssh->kex);\r
5956             s->kex_init_value = SSH2_MSG_KEXDH_INIT;\r
5957             s->kex_reply_value = SSH2_MSG_KEXDH_REPLY;\r
5958             logeventf(ssh, "Using Diffie-Hellman with standard group \"%s\"",\r
5959                       ssh->kex->groupname);\r
5960         }\r
5962         logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s",\r
5963                   ssh->kex->hash->text_name);\r
5964         /*\r
5965          * Now generate and send e for Diffie-Hellman.\r
5966          */\r
5967         set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */\r
5968         s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2);\r
5969         s->pktout = ssh2_pkt_init(s->kex_init_value);\r
5970         ssh2_pkt_addmp(s->pktout, s->e);\r
5971         ssh2_pkt_send_noqueue(ssh, s->pktout);\r
5973         set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */\r
5974         crWaitUntil(pktin);\r
5975         if (pktin->type != s->kex_reply_value) {\r
5976             bombout(("expected key exchange reply packet from server"));\r
5977             crStop(0);\r
5978         }\r
5979         set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */\r
5980         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
5981         s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen);\r
5982         s->f = ssh2_pkt_getmp(pktin);\r
5983         if (!s->f) {\r
5984             bombout(("unable to parse key exchange reply packet"));\r
5985             crStop(0);\r
5986         }\r
5987         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
5989         s->K = dh_find_K(ssh->kex_ctx, s->f);\r
5991         /* We assume everything from now on will be quick, and it might\r
5992          * involve user interaction. */\r
5993         set_busy_status(ssh->frontend, BUSY_NOT);\r
5995         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);\r
5996         if (!ssh->kex->pdata) {\r
5997             hash_uint32(ssh->kex->hash, ssh->exhash, s->pbits);\r
5998             hash_mpint(ssh->kex->hash, ssh->exhash, s->p);\r
5999             hash_mpint(ssh->kex->hash, ssh->exhash, s->g);\r
6000         }\r
6001         hash_mpint(ssh->kex->hash, ssh->exhash, s->e);\r
6002         hash_mpint(ssh->kex->hash, ssh->exhash, s->f);\r
6004         dh_cleanup(ssh->kex_ctx);\r
6005         freebn(s->f);\r
6006         if (!ssh->kex->pdata) {\r
6007             freebn(s->g);\r
6008             freebn(s->p);\r
6009         }\r
6010     } else {\r
6011         logeventf(ssh, "Doing RSA key exchange with hash %s",\r
6012                   ssh->kex->hash->text_name);\r
6013         ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX;\r
6014         /*\r
6015          * RSA key exchange. First expect a KEXRSA_PUBKEY packet\r
6016          * from the server.\r
6017          */\r
6018         crWaitUntil(pktin);\r
6019         if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) {\r
6020             bombout(("expected RSA public key packet from server"));\r
6021             crStop(0);\r
6022         }\r
6024         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
6025         hash_string(ssh->kex->hash, ssh->exhash,\r
6026                     s->hostkeydata, s->hostkeylen);\r
6027         s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen);\r
6029         {\r
6030             char *keydata;\r
6031             ssh_pkt_getstring(pktin, &keydata, &s->rsakeylen);\r
6032             s->rsakeydata = snewn(s->rsakeylen, char);\r
6033             memcpy(s->rsakeydata, keydata, s->rsakeylen);\r
6034         }\r
6036         s->rsakey = ssh_rsakex_newkey(s->rsakeydata, s->rsakeylen);\r
6037         if (!s->rsakey) {\r
6038             sfree(s->rsakeydata);\r
6039             bombout(("unable to parse RSA public key from server"));\r
6040             crStop(0);\r
6041         }\r
6043         hash_string(ssh->kex->hash, ssh->exhash, s->rsakeydata, s->rsakeylen);\r
6045         /*\r
6046          * Next, set up a shared secret K, of precisely KLEN -\r
6047          * 2*HLEN - 49 bits, where KLEN is the bit length of the\r
6048          * RSA key modulus and HLEN is the bit length of the hash\r
6049          * we're using.\r
6050          */\r
6051         {\r
6052             int klen = ssh_rsakex_klen(s->rsakey);\r
6053             int nbits = klen - (2*ssh->kex->hash->hlen*8 + 49);\r
6054             int i, byte = 0;\r
6055             unsigned char *kstr1, *kstr2, *outstr;\r
6056             int kstr1len, kstr2len, outstrlen;\r
6058             s->K = bn_power_2(nbits - 1);\r
6060             for (i = 0; i < nbits; i++) {\r
6061                 if ((i & 7) == 0) {\r
6062                     byte = random_byte();\r
6063                 }\r
6064                 bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1);\r
6065             }\r
6067             /*\r
6068              * Encode this as an mpint.\r
6069              */\r
6070             kstr1 = ssh2_mpint_fmt(s->K, &kstr1len);\r
6071             kstr2 = snewn(kstr2len = 4 + kstr1len, unsigned char);\r
6072             PUT_32BIT(kstr2, kstr1len);\r
6073             memcpy(kstr2 + 4, kstr1, kstr1len);\r
6075             /*\r
6076              * Encrypt it with the given RSA key.\r
6077              */\r
6078             outstrlen = (klen + 7) / 8;\r
6079             outstr = snewn(outstrlen, unsigned char);\r
6080             ssh_rsakex_encrypt(ssh->kex->hash, kstr2, kstr2len,\r
6081                                outstr, outstrlen, s->rsakey);\r
6083             /*\r
6084              * And send it off in a return packet.\r
6085              */\r
6086             s->pktout = ssh2_pkt_init(SSH2_MSG_KEXRSA_SECRET);\r
6087             ssh2_pkt_addstring_start(s->pktout);\r
6088             ssh2_pkt_addstring_data(s->pktout, (char *)outstr, outstrlen);\r
6089             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6091             hash_string(ssh->kex->hash, ssh->exhash, outstr, outstrlen);\r
6093             sfree(kstr2);\r
6094             sfree(kstr1);\r
6095             sfree(outstr);\r
6096         }\r
6098         ssh_rsakex_freekey(s->rsakey);\r
6100         crWaitUntil(pktin);\r
6101         if (pktin->type != SSH2_MSG_KEXRSA_DONE) {\r
6102             sfree(s->rsakeydata);\r
6103             bombout(("expected signature packet from server"));\r
6104             crStop(0);\r
6105         }\r
6107         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
6109         sfree(s->rsakeydata);\r
6110     }\r
6112     hash_mpint(ssh->kex->hash, ssh->exhash, s->K);\r
6113     assert(ssh->kex->hash->hlen <= sizeof(s->exchange_hash));\r
6114     ssh->kex->hash->final(ssh->exhash, s->exchange_hash);\r
6116     ssh->kex_ctx = NULL;\r
6118 #if 0\r
6119     debug(("Exchange hash is:\n"));\r
6120     dmemdump(s->exchange_hash, ssh->kex->hash->hlen);\r
6121 #endif\r
6123     if (!s->hkey ||\r
6124         !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,\r
6125                                  (char *)s->exchange_hash,\r
6126                                  ssh->kex->hash->hlen)) {\r
6127         bombout(("Server's host key did not match the signature supplied"));\r
6128         crStop(0);\r
6129     }\r
6131     /*\r
6132      * Authenticate remote host: verify host key. (We've already\r
6133      * checked the signature of the exchange hash.)\r
6134      */\r
6135     s->keystr = ssh->hostkey->fmtkey(s->hkey);\r
6136     s->fingerprint = ssh->hostkey->fingerprint(s->hkey);\r
6137     ssh_set_frozen(ssh, 1);\r
6138     s->dlgret = verify_ssh_host_key(ssh->frontend,\r
6139                                     ssh->savedhost, ssh->savedport,\r
6140                                     ssh->hostkey->keytype, s->keystr,\r
6141                                     s->fingerprint,\r
6142                                     ssh_dialog_callback, ssh);\r
6143     if (s->dlgret < 0) {\r
6144         do {\r
6145             crReturn(0);\r
6146             if (pktin) {\r
6147                 bombout(("Unexpected data from server while waiting"\r
6148                          " for user host key response"));\r
6149                     crStop(0);\r
6150             }\r
6151         } while (pktin || inlen > 0);\r
6152         s->dlgret = ssh->user_response;\r
6153     }\r
6154     ssh_set_frozen(ssh, 0);\r
6155     if (s->dlgret == 0) {\r
6156         ssh_disconnect(ssh, "User aborted at host key verification", NULL,\r
6157                        0, TRUE);\r
6158         crStop(0);\r
6159     }\r
6160     if (!s->got_session_id) {     /* don't bother logging this in rekeys */\r
6161         logevent("Host key fingerprint is:");\r
6162         logevent(s->fingerprint);\r
6163     }\r
6164     sfree(s->fingerprint);\r
6165     sfree(s->keystr);\r
6166     ssh->hostkey->freekey(s->hkey);\r
6168     /*\r
6169      * The exchange hash from the very first key exchange is also\r
6170      * the session id, used in session key construction and\r
6171      * authentication.\r
6172      */\r
6173     if (!s->got_session_id) {\r
6174         assert(sizeof(s->exchange_hash) <= sizeof(ssh->v2_session_id));\r
6175         memcpy(ssh->v2_session_id, s->exchange_hash,\r
6176                sizeof(s->exchange_hash));\r
6177         ssh->v2_session_id_len = ssh->kex->hash->hlen;\r
6178         assert(ssh->v2_session_id_len <= sizeof(ssh->v2_session_id));\r
6179         s->got_session_id = TRUE;\r
6180     }\r
6182     /*\r
6183      * Send SSH2_MSG_NEWKEYS.\r
6184      */\r
6185     s->pktout = ssh2_pkt_init(SSH2_MSG_NEWKEYS);\r
6186     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6187     ssh->outgoing_data_size = 0;       /* start counting from here */\r
6189     /*\r
6190      * We've sent client NEWKEYS, so create and initialise\r
6191      * client-to-server session keys.\r
6192      */\r
6193     if (ssh->cs_cipher_ctx)\r
6194         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
6195     ssh->cscipher = s->cscipher_tobe;\r
6196     ssh->cs_cipher_ctx = ssh->cscipher->make_context();\r
6198     if (ssh->cs_mac_ctx)\r
6199         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
6200     ssh->csmac = s->csmac_tobe;\r
6201     ssh->cs_mac_ctx = ssh->csmac->make_context();\r
6203     if (ssh->cs_comp_ctx)\r
6204         ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
6205     ssh->cscomp = s->cscomp_tobe;\r
6206     ssh->cs_comp_ctx = ssh->cscomp->compress_init();\r
6208     /*\r
6209      * Set IVs on client-to-server keys. Here we use the exchange\r
6210      * hash from the _first_ key exchange.\r
6211      */\r
6212     {\r
6213         unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];\r
6214         assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6215         ssh2_mkkey(ssh,s->K,s->exchange_hash,'C',keyspace);\r
6216         assert((ssh->cscipher->keylen+7) / 8 <=\r
6217                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6218         ssh->cscipher->setkey(ssh->cs_cipher_ctx, keyspace);\r
6219         ssh2_mkkey(ssh,s->K,s->exchange_hash,'A',keyspace);\r
6220         assert(ssh->cscipher->blksize <=\r
6221                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6222         ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace);\r
6223         ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace);\r
6224         assert(ssh->csmac->len <=\r
6225                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6226         ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace);\r
6227         memset(keyspace, 0, sizeof(keyspace));\r
6228     }\r
6230     logeventf(ssh, "Initialised %.200s client->server encryption",\r
6231               ssh->cscipher->text_name);\r
6232     logeventf(ssh, "Initialised %.200s client->server MAC algorithm",\r
6233               ssh->csmac->text_name);\r
6234     if (ssh->cscomp->text_name)\r
6235         logeventf(ssh, "Initialised %s compression",\r
6236                   ssh->cscomp->text_name);\r
6238     /*\r
6239      * Now our end of the key exchange is complete, we can send all\r
6240      * our queued higher-layer packets.\r
6241      */\r
6242     ssh->queueing = FALSE;\r
6243     ssh2_pkt_queuesend(ssh);\r
6245     /*\r
6246      * Expect SSH2_MSG_NEWKEYS from server.\r
6247      */\r
6248     crWaitUntil(pktin);\r
6249     if (pktin->type != SSH2_MSG_NEWKEYS) {\r
6250         bombout(("expected new-keys packet from server"));\r
6251         crStop(0);\r
6252     }\r
6253     ssh->incoming_data_size = 0;       /* start counting from here */\r
6255     /*\r
6256      * We've seen server NEWKEYS, so create and initialise\r
6257      * server-to-client session keys.\r
6258      */\r
6259     if (ssh->sc_cipher_ctx)\r
6260         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
6261     ssh->sccipher = s->sccipher_tobe;\r
6262     ssh->sc_cipher_ctx = ssh->sccipher->make_context();\r
6264     if (ssh->sc_mac_ctx)\r
6265         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
6266     ssh->scmac = s->scmac_tobe;\r
6267     ssh->sc_mac_ctx = ssh->scmac->make_context();\r
6269     if (ssh->sc_comp_ctx)\r
6270         ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
6271     ssh->sccomp = s->sccomp_tobe;\r
6272     ssh->sc_comp_ctx = ssh->sccomp->decompress_init();\r
6274     /*\r
6275      * Set IVs on server-to-client keys. Here we use the exchange\r
6276      * hash from the _first_ key exchange.\r
6277      */\r
6278     {\r
6279         unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];\r
6280         assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6281         ssh2_mkkey(ssh,s->K,s->exchange_hash,'D',keyspace);\r
6282         assert((ssh->sccipher->keylen+7) / 8 <=\r
6283                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6284         ssh->sccipher->setkey(ssh->sc_cipher_ctx, keyspace);\r
6285         ssh2_mkkey(ssh,s->K,s->exchange_hash,'B',keyspace);\r
6286         assert(ssh->sccipher->blksize <=\r
6287                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6288         ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace);\r
6289         ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace);\r
6290         assert(ssh->scmac->len <=\r
6291                ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);\r
6292         ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace);\r
6293         memset(keyspace, 0, sizeof(keyspace));\r
6294     }\r
6295     logeventf(ssh, "Initialised %.200s server->client encryption",\r
6296               ssh->sccipher->text_name);\r
6297     logeventf(ssh, "Initialised %.200s server->client MAC algorithm",\r
6298               ssh->scmac->text_name);\r
6299     if (ssh->sccomp->text_name)\r
6300         logeventf(ssh, "Initialised %s decompression",\r
6301                   ssh->sccomp->text_name);\r
6303     /*\r
6304      * Free shared secret.\r
6305      */\r
6306     freebn(s->K);\r
6308     /*\r
6309      * Key exchange is over. Loop straight back round if we have a\r
6310      * deferred rekey reason.\r
6311      */\r
6312     if (ssh->deferred_rekey_reason) {\r
6313         logevent(ssh->deferred_rekey_reason);\r
6314         pktin = NULL;\r
6315         ssh->deferred_rekey_reason = NULL;\r
6316         goto begin_key_exchange;\r
6317     }\r
6319     /*\r
6320      * Otherwise, schedule a timer for our next rekey.\r
6321      */\r
6322     ssh->kex_in_progress = FALSE;\r
6323     ssh->last_rekey = GETTICKCOUNT();\r
6324     if (ssh->cfg.ssh_rekey_time != 0)\r
6325         ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC,\r
6326                                          ssh2_timer, ssh);\r
6328     /*\r
6329      * If this is the first key exchange phase, we must pass the\r
6330      * SSH2_MSG_NEWKEYS packet to the next layer, not because it\r
6331      * wants to see it but because it will need time to initialise\r
6332      * itself before it sees an actual packet. In subsequent key\r
6333      * exchange phases, we don't pass SSH2_MSG_NEWKEYS on, because\r
6334      * it would only confuse the layer above.\r
6335      */\r
6336     if (s->activated_authconn) {\r
6337         crReturn(0);\r
6338     }\r
6339     s->activated_authconn = TRUE;\r
6341     /*\r
6342      * Now we're encrypting. Begin returning 1 to the protocol main\r
6343      * function so that other things can run on top of the\r
6344      * transport. If we ever see a KEXINIT, we must go back to the\r
6345      * start.\r
6346      * \r
6347      * We _also_ go back to the start if we see pktin==NULL and\r
6348      * inlen negative, because this is a special signal meaning\r
6349      * `initiate client-driven rekey', and `in' contains a message\r
6350      * giving the reason for the rekey.\r
6351      *\r
6352      * inlen==-1 means always initiate a rekey;\r
6353      * inlen==-2 means that userauth has completed successfully and\r
6354      *   we should consider rekeying (for delayed compression).\r
6355      */\r
6356     while (!((pktin && pktin->type == SSH2_MSG_KEXINIT) ||\r
6357              (!pktin && inlen < 0))) {\r
6358         wait_for_rekey:\r
6359         crReturn(1);\r
6360     }\r
6361     if (pktin) {\r
6362         logevent("Server initiated key re-exchange");\r
6363     } else {\r
6364         if (inlen == -2) {\r
6365             /* \r
6366              * authconn has seen a USERAUTH_SUCCEEDED. Time to enable\r
6367              * delayed compression, if it's available.\r
6368              *\r
6369              * draft-miller-secsh-compression-delayed-00 says that you\r
6370              * negotiate delayed compression in the first key exchange, and\r
6371              * both sides start compressing when the server has sent\r
6372              * USERAUTH_SUCCESS. This has a race condition -- the server\r
6373              * can't know when the client has seen it, and thus which incoming\r
6374              * packets it should treat as compressed.\r
6375              *\r
6376              * Instead, we do the initial key exchange without offering the\r
6377              * delayed methods, but note if the server offers them; when we\r
6378              * get here, if a delayed method was available that was higher\r
6379              * on our list than what we got, we initiate a rekey in which we\r
6380              * _do_ list the delayed methods (and hopefully get it as a\r
6381              * result). Subsequent rekeys will do the same.\r
6382              */\r
6383             assert(!s->userauth_succeeded); /* should only happen once */\r
6384             s->userauth_succeeded = TRUE;\r
6385             if (!s->pending_compression)\r
6386                 /* Can't see any point rekeying. */\r
6387                 goto wait_for_rekey;       /* this is utterly horrid */\r
6388             /* else fall through to rekey... */\r
6389             s->pending_compression = FALSE;\r
6390         }\r
6391         /*\r
6392          * Now we've decided to rekey.\r
6393          *\r
6394          * Special case: if the server bug is set that doesn't\r
6395          * allow rekeying, we give a different log message and\r
6396          * continue waiting. (If such a server _initiates_ a rekey,\r
6397          * we process it anyway!)\r
6398          */\r
6399         if ((ssh->remote_bugs & BUG_SSH2_REKEY)) {\r
6400             logeventf(ssh, "Server bug prevents key re-exchange (%s)",\r
6401                       (char *)in);\r
6402             /* Reset the counters, so that at least this message doesn't\r
6403              * hit the event log _too_ often. */\r
6404             ssh->outgoing_data_size = 0;\r
6405             ssh->incoming_data_size = 0;\r
6406             if (ssh->cfg.ssh_rekey_time != 0) {\r
6407                 ssh->next_rekey =\r
6408                     schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC,\r
6409                                    ssh2_timer, ssh);\r
6410             }\r
6411             goto wait_for_rekey;       /* this is still utterly horrid */\r
6412         } else {\r
6413             logeventf(ssh, "Initiating key re-exchange (%s)", (char *)in);\r
6414         }\r
6415     }\r
6416     goto begin_key_exchange;\r
6418     crFinish(1);\r
6421 /*\r
6422  * Add data to an SSH-2 channel output buffer.\r
6423  */\r
6424 static void ssh2_add_channel_data(struct ssh_channel *c, char *buf,\r
6425                                   int len)\r
6427     bufchain_add(&c->v.v2.outbuffer, buf, len);\r
6430 /*\r
6431  * Attempt to send data on an SSH-2 channel.\r
6432  */\r
6433 static int ssh2_try_send(struct ssh_channel *c)\r
6435     Ssh ssh = c->ssh;\r
6436     struct Packet *pktout;\r
6438     while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) {\r
6439         int len;\r
6440         void *data;\r
6441         bufchain_prefix(&c->v.v2.outbuffer, &data, &len);\r
6442         if ((unsigned)len > c->v.v2.remwindow)\r
6443             len = c->v.v2.remwindow;\r
6444         if ((unsigned)len > c->v.v2.remmaxpkt)\r
6445             len = c->v.v2.remmaxpkt;\r
6446         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);\r
6447         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6448         ssh2_pkt_addstring_start(pktout);\r
6449         dont_log_data(ssh, pktout, PKTLOG_OMIT);\r
6450         ssh2_pkt_addstring_data(pktout, data, len);\r
6451         end_log_omission(ssh, pktout);\r
6452         ssh2_pkt_send(ssh, pktout);\r
6453         bufchain_consume(&c->v.v2.outbuffer, len);\r
6454         c->v.v2.remwindow -= len;\r
6455     }\r
6457     /*\r
6458      * After having sent as much data as we can, return the amount\r
6459      * still buffered.\r
6460      */\r
6461     return bufchain_size(&c->v.v2.outbuffer);\r
6464 static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c)\r
6466     int bufsize;\r
6467     if (c->closes)\r
6468         return;                        /* don't send on closing channels */\r
6469     bufsize = ssh2_try_send(c);\r
6470     if (bufsize == 0) {\r
6471         switch (c->type) {\r
6472           case CHAN_MAINSESSION:\r
6473             /* stdin need not receive an unthrottle\r
6474              * notification since it will be polled */\r
6475             break;\r
6476           case CHAN_X11:\r
6477             x11_unthrottle(c->u.x11.s);\r
6478             break;\r
6479           case CHAN_AGENT:\r
6480             /* agent sockets are request/response and need no\r
6481              * buffer management */\r
6482             break;\r
6483           case CHAN_SOCKDATA:\r
6484             pfd_unthrottle(c->u.pfd.s);\r
6485             break;\r
6486         }\r
6487     }\r
6489     /*\r
6490      * If we've emptied the channel's output buffer and there's a\r
6491      * pending close event, start the channel-closing procedure.\r
6492      */\r
6493     if (c->pending_close && bufchain_size(&c->v.v2.outbuffer) == 0) {\r
6494         struct Packet *pktout;\r
6495         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
6496         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6497         ssh2_pkt_send(ssh, pktout);\r
6498         c->closes = 1;\r
6499         c->pending_close = FALSE;\r
6500     }\r
6503 /*\r
6504  * Set up most of a new ssh_channel for SSH-2.\r
6505  */\r
6506 static void ssh2_channel_init(struct ssh_channel *c)\r
6508     Ssh ssh = c->ssh;\r
6509     c->localid = alloc_channel_id(ssh);\r
6510     c->closes = 0;\r
6511     c->pending_close = FALSE;\r
6512     c->throttling_conn = FALSE;\r
6513     c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =\r
6514         ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;\r
6515     c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL;\r
6516     c->v.v2.throttle_state = UNTHROTTLED;\r
6517     bufchain_init(&c->v.v2.outbuffer);\r
6520 /*\r
6521  * Potentially enlarge the window on an SSH-2 channel.\r
6522  */\r
6523 static void ssh2_set_window(struct ssh_channel *c, int newwin)\r
6525     Ssh ssh = c->ssh;\r
6527     /*\r
6528      * Never send WINDOW_ADJUST for a channel that the remote side\r
6529      * already thinks it's closed; there's no point, since it won't\r
6530      * be sending any more data anyway.\r
6531      */\r
6532     if (c->closes != 0)\r
6533         return;\r
6535     /*\r
6536      * If the remote end has a habit of ignoring maxpkt, limit the\r
6537      * window so that it has no choice (assuming it doesn't ignore the\r
6538      * window as well).\r
6539      */\r
6540     if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT)\r
6541         newwin = OUR_V2_MAXPKT;\r
6542         \r
6544     /*\r
6545      * Only send a WINDOW_ADJUST if there's significantly more window\r
6546      * available than the other end thinks there is.  This saves us\r
6547      * sending a WINDOW_ADJUST for every character in a shell session.\r
6548      *\r
6549      * "Significant" is arbitrarily defined as half the window size.\r
6550      */\r
6551     if (newwin / 2 >= c->v.v2.locwindow) {\r
6552         struct Packet *pktout;\r
6553         struct winadj *wa;\r
6555         /*\r
6556          * In order to keep track of how much window the client\r
6557          * actually has available, we'd like it to acknowledge each\r
6558          * WINDOW_ADJUST.  We can't do that directly, so we accompany\r
6559          * it with a CHANNEL_REQUEST that has to be acknowledged.\r
6560          *\r
6561          * This is only necessary if we're opening the window wide.\r
6562          * If we're not, then throughput is being constrained by\r
6563          * something other than the maximum window size anyway.\r
6564          *\r
6565          * We also only send this if the main channel has finished its\r
6566          * initial CHANNEL_REQUESTs and installed the default\r
6567          * CHANNEL_FAILURE handler, so as not to risk giving it\r
6568          * unexpected CHANNEL_FAILUREs.\r
6569          */\r
6570         if (newwin == c->v.v2.locmaxwin &&\r
6571             ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE]) {\r
6572             pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
6573             ssh2_pkt_adduint32(pktout, c->remoteid);\r
6574             ssh2_pkt_addstring(pktout, "winadj@putty.projects.tartarus.org");\r
6575             ssh2_pkt_addbool(pktout, TRUE);\r
6576             ssh2_pkt_send(ssh, pktout);\r
6578             /*\r
6579              * CHANNEL_FAILURE doesn't come with any indication of\r
6580              * what message caused it, so we have to keep track of the\r
6581              * outstanding CHANNEL_REQUESTs ourselves.\r
6582              */\r
6583             wa = snew(struct winadj);\r
6584             wa->size = newwin - c->v.v2.locwindow;\r
6585             wa->next = NULL;\r
6586             if (!c->v.v2.winadj_head)\r
6587                 c->v.v2.winadj_head = wa;\r
6588             else\r
6589                 c->v.v2.winadj_tail->next = wa;\r
6590             c->v.v2.winadj_tail = wa;\r
6591             if (c->v.v2.throttle_state != UNTHROTTLED)\r
6592                 c->v.v2.throttle_state = UNTHROTTLING;\r
6593         } else {\r
6594             /* Pretend the WINDOW_ADJUST was acked immediately. */\r
6595             c->v.v2.remlocwin = newwin;\r
6596             c->v.v2.throttle_state = THROTTLED;\r
6597         }\r
6598         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
6599         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6600         ssh2_pkt_adduint32(pktout, newwin - c->v.v2.locwindow);\r
6601         ssh2_pkt_send(ssh, pktout);\r
6602         c->v.v2.locwindow = newwin;\r
6603     }\r
6606 /*\r
6607  * Find the channel associated with a message.  If there's no channel,\r
6608  * or it's not properly open, make a noise about it and return NULL.\r
6609  */\r
6610 static struct ssh_channel *ssh2_channel_msg(Ssh ssh, struct Packet *pktin)\r
6612     unsigned localid = ssh_pkt_getuint32(pktin);\r
6613     struct ssh_channel *c;\r
6615     c = find234(ssh->channels, &localid, ssh_channelfind);\r
6616     if (!c ||\r
6617         (c->halfopen && pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION &&\r
6618          pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE)) {\r
6619         char *buf = dupprintf("Received %s for %s channel %u",\r
6620                               ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
6621                                             pktin->type),\r
6622                               c ? "half-open" : "nonexistent", localid);\r
6623         ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
6624         sfree(buf);\r
6625         return NULL;\r
6626     }\r
6627     return c;\r
6630 static int ssh2_handle_winadj_response(struct ssh_channel *c)\r
6632     struct winadj *wa = c->v.v2.winadj_head;\r
6633     if (!wa)\r
6634         return FALSE;\r
6635     c->v.v2.winadj_head = wa->next;\r
6636     c->v.v2.remlocwin += wa->size;\r
6637     sfree(wa);\r
6638     /*\r
6639      * winadj messages are only sent when the window is fully open, so\r
6640      * if we get an ack of one, we know any pending unthrottle is\r
6641      * complete.\r
6642      */\r
6643     if (c->v.v2.throttle_state == UNTHROTTLING)\r
6644         c->v.v2.throttle_state = UNTHROTTLED;\r
6645     return TRUE;\r
6648 static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin)\r
6650     /*\r
6651      * This should never get called.  All channel requests are either\r
6652      * sent with want_reply false, are sent before this handler gets\r
6653      * installed, or are "winadj@putty" requests, which servers should\r
6654      * never respond to with success.\r
6655      *\r
6656      * However, at least one server ("boks_sshd") is known to return\r
6657      * SUCCESS for channel requests it's never heard of, such as\r
6658      * "winadj@putty". Raised with foxt.com as bug 090916-090424, but\r
6659      * for the sake of a quiet life, we handle it just the same as the\r
6660      * expected FAILURE.\r
6661      */\r
6662     struct ssh_channel *c;\r
6664     c = ssh2_channel_msg(ssh, pktin);\r
6665     if (!c)\r
6666         return;\r
6667     if (!ssh2_handle_winadj_response(c))\r
6668         ssh_disconnect(ssh, NULL,\r
6669                        "Received unsolicited SSH_MSG_CHANNEL_SUCCESS",\r
6670                        SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
6673 static void ssh2_msg_channel_failure(Ssh ssh, struct Packet *pktin)\r
6675     /*\r
6676      * The only time this should get called is for "winadj@putty"\r
6677      * messages sent above.  All other channel requests are either\r
6678      * sent with want_reply false or are sent before this handler gets\r
6679      * installed.\r
6680      */\r
6681     struct ssh_channel *c;\r
6683     c = ssh2_channel_msg(ssh, pktin);\r
6684     if (!c)\r
6685         return;\r
6686     if (!ssh2_handle_winadj_response(c))\r
6687         ssh_disconnect(ssh, NULL,\r
6688                        "Received unsolicited SSH_MSG_CHANNEL_FAILURE",\r
6689                        SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
6692 static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)\r
6694     struct ssh_channel *c;\r
6695     c = ssh2_channel_msg(ssh, pktin);\r
6696     if (!c)\r
6697         return;\r
6698     if (!c->closes) {\r
6699         c->v.v2.remwindow += ssh_pkt_getuint32(pktin);\r
6700         ssh2_try_send_and_unthrottle(ssh, c);\r
6701     }\r
6704 static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
6706     char *data;\r
6707     int length;\r
6708     struct ssh_channel *c;\r
6709     c = ssh2_channel_msg(ssh, pktin);\r
6710     if (!c)\r
6711         return;\r
6712     if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&\r
6713         ssh_pkt_getuint32(pktin) != SSH2_EXTENDED_DATA_STDERR)\r
6714         return;                        /* extended but not stderr */\r
6715     ssh_pkt_getstring(pktin, &data, &length);\r
6716     if (data) {\r
6717         int bufsize = 0;\r
6718         c->v.v2.locwindow -= length;\r
6719         c->v.v2.remlocwin -= length;\r
6720         switch (c->type) {\r
6721           case CHAN_MAINSESSION:\r
6722             bufsize =\r
6723                 from_backend(ssh->frontend, pktin->type ==\r
6724                              SSH2_MSG_CHANNEL_EXTENDED_DATA,\r
6725                              data, length);\r
6726             break;\r
6727           case CHAN_X11:\r
6728             bufsize = x11_send(c->u.x11.s, data, length);\r
6729             break;\r
6730           case CHAN_SOCKDATA:\r
6731             bufsize = pfd_send(c->u.pfd.s, data, length);\r
6732             break;\r
6733           case CHAN_AGENT:\r
6734             while (length > 0) {\r
6735                 if (c->u.a.lensofar < 4) {\r
6736                     unsigned int l = min(4 - c->u.a.lensofar,\r
6737                                          (unsigned)length);\r
6738                     memcpy(c->u.a.msglen + c->u.a.lensofar,\r
6739                            data, l);\r
6740                     data += l;\r
6741                     length -= l;\r
6742                     c->u.a.lensofar += l;\r
6743                 }\r
6744                 if (c->u.a.lensofar == 4) {\r
6745                     c->u.a.totallen =\r
6746                         4 + GET_32BIT(c->u.a.msglen);\r
6747                     c->u.a.message = snewn(c->u.a.totallen,\r
6748                                            unsigned char);\r
6749                     memcpy(c->u.a.message, c->u.a.msglen, 4);\r
6750                 }\r
6751                 if (c->u.a.lensofar >= 4 && length > 0) {\r
6752                     unsigned int l =\r
6753                         min(c->u.a.totallen - c->u.a.lensofar,\r
6754                             (unsigned)length);\r
6755                     memcpy(c->u.a.message + c->u.a.lensofar,\r
6756                            data, l);\r
6757                     data += l;\r
6758                     length -= l;\r
6759                     c->u.a.lensofar += l;\r
6760                 }\r
6761                 if (c->u.a.lensofar == c->u.a.totallen) {\r
6762                     void *reply;\r
6763                     int replylen;\r
6764                     if (agent_query(c->u.a.message,\r
6765                                     c->u.a.totallen,\r
6766                                     &reply, &replylen,\r
6767                                     ssh_agentf_callback, c))\r
6768                         ssh_agentf_callback(c, reply, replylen);\r
6769                     sfree(c->u.a.message);\r
6770                     c->u.a.lensofar = 0;\r
6771                 }\r
6772             }\r
6773             bufsize = 0;\r
6774             break;\r
6775         }\r
6776         /*\r
6777          * If it looks like the remote end hit the end of its window,\r
6778          * and we didn't want it to do that, think about using a\r
6779          * larger window.\r
6780          */\r
6781         if (c->v.v2.remlocwin <= 0 && c->v.v2.throttle_state == UNTHROTTLED &&\r
6782             c->v.v2.locmaxwin < 0x40000000)\r
6783             c->v.v2.locmaxwin += OUR_V2_WINSIZE;\r
6784         /*\r
6785          * If we are not buffering too much data,\r
6786          * enlarge the window again at the remote side.\r
6787          * If we are buffering too much, we may still\r
6788          * need to adjust the window if the server's\r
6789          * sent excess data.\r
6790          */\r
6791         ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ?\r
6792                         c->v.v2.locmaxwin - bufsize : 0);\r
6793         /*\r
6794          * If we're either buffering way too much data, or if we're\r
6795          * buffering anything at all and we're in "simple" mode,\r
6796          * throttle the whole channel.\r
6797          */\r
6798         if ((bufsize > c->v.v2.locmaxwin ||\r
6799              (ssh->cfg.ssh_simple && bufsize > 0)) &&\r
6800             !c->throttling_conn) {\r
6801             c->throttling_conn = 1;\r
6802             ssh_throttle_conn(ssh, +1);\r
6803         }\r
6804     }\r
6807 static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin)\r
6809     struct ssh_channel *c;\r
6811     c = ssh2_channel_msg(ssh, pktin);\r
6812     if (!c)\r
6813         return;\r
6815     if (c->type == CHAN_X11) {\r
6816         /*\r
6817          * Remote EOF on an X11 channel means we should\r
6818          * wrap up and close the channel ourselves.\r
6819          */\r
6820         x11_close(c->u.x11.s);\r
6821         c->u.x11.s = NULL;\r
6822         sshfwd_close(c);\r
6823     } else if (c->type == CHAN_AGENT) {\r
6824         sshfwd_close(c);\r
6825     } else if (c->type == CHAN_SOCKDATA) {\r
6826         pfd_close(c->u.pfd.s);\r
6827         c->u.pfd.s = NULL;\r
6828         sshfwd_close(c);\r
6829     }\r
6832 static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
6834     struct ssh_channel *c;\r
6835     struct Packet *pktout;\r
6837     c = ssh2_channel_msg(ssh, pktin);\r
6838     if (!c)\r
6839         return;\r
6840     /* Do pre-close processing on the channel. */\r
6841     switch (c->type) {\r
6842       case CHAN_MAINSESSION:\r
6843         ssh->mainchan = NULL;\r
6844         update_specials_menu(ssh->frontend);\r
6845         break;\r
6846       case CHAN_X11:\r
6847         if (c->u.x11.s != NULL)\r
6848             x11_close(c->u.x11.s);\r
6849         sshfwd_close(c);\r
6850         break;\r
6851       case CHAN_AGENT:\r
6852         sshfwd_close(c);\r
6853         break;\r
6854       case CHAN_SOCKDATA:\r
6855         if (c->u.pfd.s != NULL)\r
6856             pfd_close(c->u.pfd.s);\r
6857         sshfwd_close(c);\r
6858         break;\r
6859     }\r
6860     if (c->closes == 0) {\r
6861         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
6862         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6863         ssh2_pkt_send(ssh, pktout);\r
6864     }\r
6865     del234(ssh->channels, c);\r
6866     bufchain_clear(&c->v.v2.outbuffer);\r
6867     sfree(c);\r
6869     /*\r
6870      * See if that was the last channel left open.\r
6871      * (This is only our termination condition if we're\r
6872      * not running in -N mode.)\r
6873      */\r
6874     if (!ssh->cfg.ssh_no_shell && count234(ssh->channels) == 0) {\r
6875         /*\r
6876          * We used to send SSH_MSG_DISCONNECT here,\r
6877          * because I'd believed that _every_ conforming\r
6878          * SSH-2 connection had to end with a disconnect\r
6879          * being sent by at least one side; apparently\r
6880          * I was wrong and it's perfectly OK to\r
6881          * unceremoniously slam the connection shut\r
6882          * when you're done, and indeed OpenSSH feels\r
6883          * this is more polite than sending a\r
6884          * DISCONNECT. So now we don't.\r
6885          */\r
6886         ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE);\r
6887     }\r
6890 static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
6892     struct ssh_channel *c;\r
6893     struct Packet *pktout;\r
6895     c = ssh2_channel_msg(ssh, pktin);\r
6896     if (!c)\r
6897         return;\r
6898     if (c->type != CHAN_SOCKDATA_DORMANT)\r
6899         return;                        /* dunno why they're confirming this */\r
6900     c->remoteid = ssh_pkt_getuint32(pktin);\r
6901     c->halfopen = FALSE;\r
6902     c->type = CHAN_SOCKDATA;\r
6903     c->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
6904     c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
6905     if (c->u.pfd.s)\r
6906         pfd_confirm(c->u.pfd.s);\r
6907     if (c->closes) {\r
6908         /*\r
6909          * We have a pending close on this channel,\r
6910          * which we decided on before the server acked\r
6911          * the channel open. So now we know the\r
6912          * remoteid, we can close it again.\r
6913          */\r
6914         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
6915         ssh2_pkt_adduint32(pktout, c->remoteid);\r
6916         ssh2_pkt_send(ssh, pktout);\r
6917     }\r
6920 static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
6922     static const char *const reasons[] = {\r
6923         "<unknown reason code>",\r
6924             "Administratively prohibited",\r
6925             "Connect failed",\r
6926             "Unknown channel type",\r
6927             "Resource shortage",\r
6928     };\r
6929     unsigned reason_code;\r
6930     char *reason_string;\r
6931     int reason_length;\r
6932     struct ssh_channel *c;\r
6933     c = ssh2_channel_msg(ssh, pktin);\r
6934     if (!c)\r
6935         return;\r
6936     if (c->type != CHAN_SOCKDATA_DORMANT)\r
6937         return;                        /* dunno why they're failing this */\r
6939     reason_code = ssh_pkt_getuint32(pktin);\r
6940     if (reason_code >= lenof(reasons))\r
6941         reason_code = 0; /* ensure reasons[reason_code] in range */\r
6942     ssh_pkt_getstring(pktin, &reason_string, &reason_length);\r
6943     logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",\r
6944               reasons[reason_code], reason_length, reason_string);\r
6946     pfd_close(c->u.pfd.s);\r
6948     del234(ssh->channels, c);\r
6949     sfree(c);\r
6952 static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin)\r
6954     char *type;\r
6955     int typelen, want_reply;\r
6956     int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */\r
6957     struct ssh_channel *c;\r
6958     struct Packet *pktout;\r
6960     c = ssh2_channel_msg(ssh, pktin);\r
6961     if (!c)\r
6962         return;\r
6963     ssh_pkt_getstring(pktin, &type, &typelen);\r
6964     want_reply = ssh2_pkt_getbool(pktin);\r
6966     /*\r
6967      * Having got the channel number, we now look at\r
6968      * the request type string to see if it's something\r
6969      * we recognise.\r
6970      */\r
6971     if (c == ssh->mainchan) {\r
6972         /*\r
6973          * We recognise "exit-status" and "exit-signal" on\r
6974          * the primary channel.\r
6975          */\r
6976         if (typelen == 11 &&\r
6977             !memcmp(type, "exit-status", 11)) {\r
6979             ssh->exitcode = ssh_pkt_getuint32(pktin);\r
6980             logeventf(ssh, "Server sent command exit status %d",\r
6981                       ssh->exitcode);\r
6982             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
6984         } else if (typelen == 11 &&\r
6985                    !memcmp(type, "exit-signal", 11)) {\r
6987             int is_plausible = TRUE, is_int = FALSE;\r
6988             char *fmt_sig = "", *fmt_msg = "";\r
6989             char *msg;\r
6990             int msglen = 0, core = FALSE;\r
6991             /* ICK: older versions of OpenSSH (e.g. 3.4p1)\r
6992              * provide an `int' for the signal, despite its\r
6993              * having been a `string' in the drafts of RFC 4254 since at\r
6994              * least 2001. (Fixed in session.c 1.147.) Try to\r
6995              * infer which we can safely parse it as. */\r
6996             {\r
6997                 unsigned char *p = pktin->body +\r
6998                     pktin->savedpos;\r
6999                 long len = pktin->length - pktin->savedpos;\r
7000                 unsigned long num = GET_32BIT(p); /* what is it? */\r
7001                 /* If it's 0, it hardly matters; assume string */\r
7002                 if (num == 0) {\r
7003                     is_int = FALSE;\r
7004                 } else {\r
7005                     int maybe_int = FALSE, maybe_str = FALSE;\r
7006 #define CHECK_HYPOTHESIS(offset, result) \\r
7007     do { \\r
7008         long q = offset; \\r
7009         if (q >= 0 && q+4 <= len) { \\r
7010             q = q + 4 + GET_32BIT(p+q); \\r
7011             if (q >= 0 && q+4 <= len && \\r
7012                     ((q = q + 4 + GET_32BIT(p+q))!= 0) && q == len) \\r
7013                 result = TRUE; \\r
7014         } \\r
7015     } while(0)\r
7016                     CHECK_HYPOTHESIS(4+1, maybe_int);\r
7017                     CHECK_HYPOTHESIS(4+num+1, maybe_str);\r
7018 #undef CHECK_HYPOTHESIS\r
7019                     if (maybe_int && !maybe_str)\r
7020                         is_int = TRUE;\r
7021                     else if (!maybe_int && maybe_str)\r
7022                         is_int = FALSE;\r
7023                     else\r
7024                         /* Crikey. Either or neither. Panic. */\r
7025                         is_plausible = FALSE;\r
7026                 }\r
7027             }\r
7028             ssh->exitcode = 128;       /* means `unknown signal' */\r
7029             if (is_plausible) {\r
7030                 if (is_int) {\r
7031                     /* Old non-standard OpenSSH. */\r
7032                     int signum = ssh_pkt_getuint32(pktin);\r
7033                     fmt_sig = dupprintf(" %d", signum);\r
7034                     ssh->exitcode = 128 + signum;\r
7035                 } else {\r
7036                     /* As per RFC 4254. */\r
7037                     char *sig;\r
7038                     int siglen;\r
7039                     ssh_pkt_getstring(pktin, &sig, &siglen);\r
7040                     /* Signal name isn't supposed to be blank, but\r
7041                      * let's cope gracefully if it is. */\r
7042                     if (siglen) {\r
7043                         fmt_sig = dupprintf(" \"%.*s\"",\r
7044                                             siglen, sig);\r
7045                     }\r
7047                     /*\r
7048                      * Really hideous method of translating the\r
7049                      * signal description back into a locally\r
7050                      * meaningful number.\r
7051                      */\r
7053                     if (0)\r
7054                         ;\r
7055 #define TRANSLATE_SIGNAL(s) \\r
7056     else if (siglen == lenof(#s)-1 && !memcmp(sig, #s, siglen)) \\r
7057         ssh->exitcode = 128 + SIG ## s\r
7058 #ifdef SIGABRT\r
7059                     TRANSLATE_SIGNAL(ABRT);\r
7060 #endif\r
7061 #ifdef SIGALRM\r
7062                     TRANSLATE_SIGNAL(ALRM);\r
7063 #endif\r
7064 #ifdef SIGFPE\r
7065                     TRANSLATE_SIGNAL(FPE);\r
7066 #endif\r
7067 #ifdef SIGHUP\r
7068                     TRANSLATE_SIGNAL(HUP);\r
7069 #endif\r
7070 #ifdef SIGILL\r
7071                     TRANSLATE_SIGNAL(ILL);\r
7072 #endif\r
7073 #ifdef SIGINT\r
7074                     TRANSLATE_SIGNAL(INT);\r
7075 #endif\r
7076 #ifdef SIGKILL\r
7077                     TRANSLATE_SIGNAL(KILL);\r
7078 #endif\r
7079 #ifdef SIGPIPE\r
7080                     TRANSLATE_SIGNAL(PIPE);\r
7081 #endif\r
7082 #ifdef SIGQUIT\r
7083                     TRANSLATE_SIGNAL(QUIT);\r
7084 #endif\r
7085 #ifdef SIGSEGV\r
7086                     TRANSLATE_SIGNAL(SEGV);\r
7087 #endif\r
7088 #ifdef SIGTERM\r
7089                     TRANSLATE_SIGNAL(TERM);\r
7090 #endif\r
7091 #ifdef SIGUSR1\r
7092                     TRANSLATE_SIGNAL(USR1);\r
7093 #endif\r
7094 #ifdef SIGUSR2\r
7095                     TRANSLATE_SIGNAL(USR2);\r
7096 #endif\r
7097 #undef TRANSLATE_SIGNAL\r
7098                     else\r
7099                         ssh->exitcode = 128;\r
7100                 }\r
7101                 core = ssh2_pkt_getbool(pktin);\r
7102                 ssh_pkt_getstring(pktin, &msg, &msglen);\r
7103                 if (msglen) {\r
7104                     fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg);\r
7105                 }\r
7106                 /* ignore lang tag */\r
7107             } /* else don't attempt to parse */\r
7108             logeventf(ssh, "Server exited on signal%s%s%s",\r
7109                       fmt_sig, core ? " (core dumped)" : "",\r
7110                       fmt_msg);\r
7111             if (*fmt_sig) sfree(fmt_sig);\r
7112             if (*fmt_msg) sfree(fmt_msg);\r
7113             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
7115         }\r
7116     } else {\r
7117         /*\r
7118          * This is a channel request we don't know\r
7119          * about, so we now either ignore the request\r
7120          * or respond with CHANNEL_FAILURE, depending\r
7121          * on want_reply.\r
7122          */\r
7123         reply = SSH2_MSG_CHANNEL_FAILURE;\r
7124     }\r
7125     if (want_reply) {\r
7126         pktout = ssh2_pkt_init(reply);\r
7127         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7128         ssh2_pkt_send(ssh, pktout);\r
7129     }\r
7132 static void ssh2_msg_global_request(Ssh ssh, struct Packet *pktin)\r
7134     char *type;\r
7135     int typelen, want_reply;\r
7136     struct Packet *pktout;\r
7138     ssh_pkt_getstring(pktin, &type, &typelen);\r
7139     want_reply = ssh2_pkt_getbool(pktin);\r
7141     /*\r
7142      * We currently don't support any global requests\r
7143      * at all, so we either ignore the request or\r
7144      * respond with REQUEST_FAILURE, depending on\r
7145      * want_reply.\r
7146      */\r
7147     if (want_reply) {\r
7148         pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE);\r
7149         ssh2_pkt_send(ssh, pktout);\r
7150     }\r
7153 static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)\r
7155     char *type;\r
7156     int typelen;\r
7157     char *peeraddr;\r
7158     int peeraddrlen;\r
7159     int peerport;\r
7160     char *error = NULL;\r
7161     struct ssh_channel *c;\r
7162     unsigned remid, winsize, pktsize;\r
7163     struct Packet *pktout;\r
7165     ssh_pkt_getstring(pktin, &type, &typelen);\r
7166     c = snew(struct ssh_channel);\r
7167     c->ssh = ssh;\r
7169     remid = ssh_pkt_getuint32(pktin);\r
7170     winsize = ssh_pkt_getuint32(pktin);\r
7171     pktsize = ssh_pkt_getuint32(pktin);\r
7173     if (typelen == 3 && !memcmp(type, "x11", 3)) {\r
7174         char *addrstr;\r
7175         const char *x11err;\r
7177         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
7178         addrstr = snewn(peeraddrlen+1, char);\r
7179         memcpy(addrstr, peeraddr, peeraddrlen);\r
7180         addrstr[peeraddrlen] = '\0';\r
7181         peerport = ssh_pkt_getuint32(pktin);\r
7183         logeventf(ssh, "Received X11 connect request from %s:%d",\r
7184                   addrstr, peerport);\r
7186         if (!ssh->X11_fwd_enabled)\r
7187             error = "X11 forwarding is not enabled";\r
7188         else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,\r
7189                                     addrstr, peerport, &ssh->cfg)) != NULL) {\r
7190             logeventf(ssh, "Local X11 connection failed: %s", x11err);\r
7191             error = "Unable to open an X11 connection";\r
7192         } else {\r
7193             logevent("Opening X11 forward connection succeeded");\r
7194             c->type = CHAN_X11;\r
7195         }\r
7197         sfree(addrstr);\r
7198     } else if (typelen == 15 &&\r
7199                !memcmp(type, "forwarded-tcpip", 15)) {\r
7200         struct ssh_rportfwd pf, *realpf;\r
7201         char *dummy;\r
7202         int dummylen;\r
7203         ssh_pkt_getstring(pktin, &dummy, &dummylen);/* skip address */\r
7204         pf.sport = ssh_pkt_getuint32(pktin);\r
7205         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
7206         peerport = ssh_pkt_getuint32(pktin);\r
7207         realpf = find234(ssh->rportfwds, &pf, NULL);\r
7208         logeventf(ssh, "Received remote port %d open request "\r
7209                   "from %s:%d", pf.sport, peeraddr, peerport);\r
7210         if (realpf == NULL) {\r
7211             error = "Remote port is not recognised";\r
7212         } else {\r
7213             const char *e = pfd_newconnect(&c->u.pfd.s,\r
7214                                            realpf->dhost,\r
7215                                            realpf->dport, c,\r
7216                                            &ssh->cfg,\r
7217                                            realpf->pfrec->addressfamily);\r
7218             logeventf(ssh, "Attempting to forward remote port to "\r
7219                       "%s:%d", realpf->dhost, realpf->dport);\r
7220             if (e != NULL) {\r
7221                 logeventf(ssh, "Port open failed: %s", e);\r
7222                 error = "Port open failed";\r
7223             } else {\r
7224                 logevent("Forwarded port opened successfully");\r
7225                 c->type = CHAN_SOCKDATA;\r
7226             }\r
7227         }\r
7228     } else if (typelen == 22 &&\r
7229                !memcmp(type, "auth-agent@openssh.com", 22)) {\r
7230         if (!ssh->agentfwd_enabled)\r
7231             error = "Agent forwarding is not enabled";\r
7232         else {\r
7233             c->type = CHAN_AGENT;       /* identify channel type */\r
7234             c->u.a.lensofar = 0;\r
7235         }\r
7236     } else {\r
7237         error = "Unsupported channel type requested";\r
7238     }\r
7240     c->remoteid = remid;\r
7241     c->halfopen = FALSE;\r
7242     if (error) {\r
7243         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
7244         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7245         ssh2_pkt_adduint32(pktout, SSH2_OPEN_CONNECT_FAILED);\r
7246         ssh2_pkt_addstring(pktout, error);\r
7247         ssh2_pkt_addstring(pktout, "en");       /* language tag */\r
7248         ssh2_pkt_send(ssh, pktout);\r
7249         logeventf(ssh, "Rejected channel open: %s", error);\r
7250         sfree(c);\r
7251     } else {\r
7252         ssh2_channel_init(c);\r
7253         c->v.v2.remwindow = winsize;\r
7254         c->v.v2.remmaxpkt = pktsize;\r
7255         add234(ssh->channels, c);\r
7256         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
7257         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7258         ssh2_pkt_adduint32(pktout, c->localid);\r
7259         ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);\r
7260         ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
7261         ssh2_pkt_send(ssh, pktout);\r
7262     }\r
7265 /*\r
7266  * Buffer banner messages for later display at some convenient point,\r
7267  * if we're going to display them.\r
7268  */\r
7269 static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin)\r
7271     /* Arbitrary limit to prevent unbounded inflation of buffer */\r
7272     if (ssh->cfg.ssh_show_banner &&\r
7273         bufchain_size(&ssh->banner) <= 131072) {\r
7274         char *banner = NULL;\r
7275         int size = 0;\r
7276         ssh_pkt_getstring(pktin, &banner, &size);\r
7277         if (banner)\r
7278             bufchain_add(&ssh->banner, banner, size);\r
7279     }\r
7282 /* Helper function to deal with sending tty modes for "pty-req" */\r
7283 static void ssh2_send_ttymode(void *data, char *mode, char *val)\r
7285     struct Packet *pktout = (struct Packet *)data;\r
7286     int i = 0;\r
7287     unsigned int arg = 0;\r
7288     while (strcmp(mode, ssh_ttymodes[i].mode) != 0) i++;\r
7289     if (i == lenof(ssh_ttymodes)) return;\r
7290     switch (ssh_ttymodes[i].type) {\r
7291       case TTY_OP_CHAR:\r
7292         arg = ssh_tty_parse_specchar(val);\r
7293         break;\r
7294       case TTY_OP_BOOL:\r
7295         arg = ssh_tty_parse_boolean(val);\r
7296         break;\r
7297     }\r
7298     ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode);\r
7299     ssh2_pkt_adduint32(pktout, arg);\r
7302 /*\r
7303  * Handle the SSH-2 userauth and connection layers.\r
7304  */\r
7305 static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,\r
7306                              struct Packet *pktin)\r
7308     struct do_ssh2_authconn_state {\r
7309         enum {\r
7310             AUTH_TYPE_NONE,\r
7311                 AUTH_TYPE_PUBLICKEY,\r
7312                 AUTH_TYPE_PUBLICKEY_OFFER_LOUD,\r
7313                 AUTH_TYPE_PUBLICKEY_OFFER_QUIET,\r
7314                 AUTH_TYPE_PASSWORD,\r
7315                 AUTH_TYPE_GSSAPI,      /* always QUIET */\r
7316                 AUTH_TYPE_KEYBOARD_INTERACTIVE,\r
7317                 AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET\r
7318         } type;\r
7319         int done_service_req;\r
7320         int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;\r
7321         int tried_pubkey_config, done_agent;\r
7322 #ifndef NO_GSSAPI\r
7323         int can_gssapi;\r
7324         int tried_gssapi;\r
7325 #endif\r
7326         int kbd_inter_refused;\r
7327         int we_are_in, userauth_success;\r
7328         prompts_t *cur_prompt;\r
7329         int num_prompts;\r
7330         char username[100];\r
7331         char *password;\r
7332         int got_username;\r
7333         void *publickey_blob;\r
7334         int publickey_bloblen;\r
7335         int publickey_encrypted;\r
7336         char *publickey_algorithm;\r
7337         char *publickey_comment;\r
7338         unsigned char agent_request[5], *agent_response, *agentp;\r
7339         int agent_responselen;\r
7340         unsigned char *pkblob_in_agent;\r
7341         int keyi, nkeys;\r
7342         char *pkblob, *alg, *commentp;\r
7343         int pklen, alglen, commentlen;\r
7344         int siglen, retlen, len;\r
7345         char *q, *agentreq, *ret;\r
7346         int try_send;\r
7347         int num_env, env_left, env_ok;\r
7348         struct Packet *pktout;\r
7349 #ifndef NO_GSSAPI\r
7350         struct ssh_gss_library *gsslib;\r
7351         Ssh_gss_ctx gss_ctx;\r
7352         Ssh_gss_buf gss_buf;\r
7353         Ssh_gss_buf gss_rcvtok, gss_sndtok;\r
7354         Ssh_gss_name gss_srv_name;\r
7355         Ssh_gss_stat gss_stat;\r
7356 #endif\r
7357     };\r
7358     crState(do_ssh2_authconn_state);\r
7360     crBegin(ssh->do_ssh2_authconn_crstate);\r
7362     s->done_service_req = FALSE;\r
7363     s->we_are_in = s->userauth_success = FALSE;\r
7364 #ifndef NO_GSSAPI\r
7365     s->tried_gssapi = FALSE;\r
7366 #endif\r
7368     if (!ssh->cfg.ssh_no_userauth) {\r
7369         /*\r
7370          * Request userauth protocol, and await a response to it.\r
7371          */\r
7372         s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
7373         ssh2_pkt_addstring(s->pktout, "ssh-userauth");\r
7374         ssh2_pkt_send(ssh, s->pktout);\r
7375         crWaitUntilV(pktin);\r
7376         if (pktin->type == SSH2_MSG_SERVICE_ACCEPT)\r
7377             s->done_service_req = TRUE;\r
7378     }\r
7379     if (!s->done_service_req) {\r
7380         /*\r
7381          * Request connection protocol directly, without authentication.\r
7382          */\r
7383         s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
7384         ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
7385         ssh2_pkt_send(ssh, s->pktout);\r
7386         crWaitUntilV(pktin);\r
7387         if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {\r
7388             s->we_are_in = TRUE; /* no auth required */\r
7389         } else {\r
7390             bombout(("Server refused service request"));\r
7391             crStopV;\r
7392         }\r
7393     }\r
7395     /* Arrange to be able to deal with any BANNERs that come in.\r
7396      * (We do this now as packets may come in during the next bit.) */\r
7397     bufchain_init(&ssh->banner);\r
7398     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] =\r
7399         ssh2_msg_userauth_banner;\r
7401     /*\r
7402      * Misc one-time setup for authentication.\r
7403      */\r
7404     s->publickey_blob = NULL;\r
7405     if (!s->we_are_in) {\r
7407         /*\r
7408          * Load the public half of any configured public key file\r
7409          * for later use.\r
7410          */\r
7411         if (!filename_is_null(ssh->cfg.keyfile)) {\r
7412             int keytype;\r
7413             logeventf(ssh, "Reading private key file \"%.150s\"",\r
7414                       filename_to_str(&ssh->cfg.keyfile));\r
7415             keytype = key_type(&ssh->cfg.keyfile);\r
7416             if (keytype == SSH_KEYTYPE_SSH2) {\r
7417                 const char *error;\r
7418                 s->publickey_blob =\r
7419                     ssh2_userkey_loadpub(&ssh->cfg.keyfile,\r
7420                                          &s->publickey_algorithm,\r
7421                                          &s->publickey_bloblen, \r
7422                                          &s->publickey_comment, &error);\r
7423                 if (s->publickey_blob) {\r
7424                     s->publickey_encrypted =\r
7425                         ssh2_userkey_encrypted(&ssh->cfg.keyfile, NULL);\r
7426                 } else {\r
7427                     char *msgbuf;\r
7428                     logeventf(ssh, "Unable to load private key (%s)", \r
7429                               error);\r
7430                     msgbuf = dupprintf("Unable to load private key file "\r
7431                                        "\"%.150s\" (%s)\r\n",\r
7432                                        filename_to_str(&ssh->cfg.keyfile),\r
7433                                        error);\r
7434                     c_write_str(ssh, msgbuf);\r
7435                     sfree(msgbuf);\r
7436                 }\r
7437             } else {\r
7438                 char *msgbuf;\r
7439                 logeventf(ssh, "Unable to use this key file (%s)",\r
7440                           key_type_to_str(keytype));\r
7441                 msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
7442                                    " (%s)\r\n",\r
7443                                    filename_to_str(&ssh->cfg.keyfile),\r
7444                                    key_type_to_str(keytype));\r
7445                 c_write_str(ssh, msgbuf);\r
7446                 sfree(msgbuf);\r
7447                 s->publickey_blob = NULL;\r
7448             }\r
7449         }\r
7451         /*\r
7452          * Find out about any keys Pageant has (but if there's a\r
7453          * public key configured, filter out all others).\r
7454          */\r
7455         s->nkeys = 0;\r
7456         s->agent_response = NULL;\r
7457         s->pkblob_in_agent = NULL;\r
7458         if (ssh->cfg.tryagent && agent_exists()) {\r
7460             void *r;\r
7462             logevent("Pageant is running. Requesting keys.");\r
7464             /* Request the keys held by the agent. */\r
7465             PUT_32BIT(s->agent_request, 1);\r
7466             s->agent_request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;\r
7467             if (!agent_query(s->agent_request, 5, &r, &s->agent_responselen,\r
7468                              ssh_agent_callback, ssh)) {\r
7469                 do {\r
7470                     crReturnV;\r
7471                     if (pktin) {\r
7472                         bombout(("Unexpected data from server while"\r
7473                                  " waiting for agent response"));\r
7474                         crStopV;\r
7475                     }\r
7476                 } while (pktin || inlen > 0);\r
7477                 r = ssh->agent_response;\r
7478                 s->agent_responselen = ssh->agent_response_len;\r
7479             }\r
7480             s->agent_response = (unsigned char *) r;\r
7481             if (s->agent_response && s->agent_responselen >= 5 &&\r
7482                 s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {\r
7483                 int keyi;\r
7484                 unsigned char *p;\r
7485                 p = s->agent_response + 5;\r
7486                 s->nkeys = GET_32BIT(p);\r
7487                 p += 4;\r
7488                 logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys);\r
7489                 if (s->publickey_blob) {\r
7490                     /* See if configured key is in agent. */\r
7491                     for (keyi = 0; keyi < s->nkeys; keyi++) {\r
7492                         s->pklen = GET_32BIT(p);\r
7493                         if (s->pklen == s->publickey_bloblen &&\r
7494                             !memcmp(p+4, s->publickey_blob,\r
7495                                     s->publickey_bloblen)) {\r
7496                             logeventf(ssh, "Pageant key #%d matches "\r
7497                                       "configured key file", keyi);\r
7498                             s->keyi = keyi;\r
7499                             s->pkblob_in_agent = p;\r
7500                             break;\r
7501                         }\r
7502                         p += 4 + s->pklen;\r
7503                         p += GET_32BIT(p) + 4; /* comment */\r
7504                     }\r
7505                     if (!s->pkblob_in_agent) {\r
7506                         logevent("Configured key file not in Pageant");\r
7507                         s->nkeys = 0;\r
7508                     }\r
7509                 }\r
7510             } else {\r
7511                 logevent("Failed to get reply from Pageant");\r
7512             }\r
7513         }\r
7515     }\r
7517     /*\r
7518      * We repeat this whole loop, including the username prompt,\r
7519      * until we manage a successful authentication. If the user\r
7520      * types the wrong _password_, they can be sent back to the\r
7521      * beginning to try another username, if this is configured on.\r
7522      * (If they specify a username in the config, they are never\r
7523      * asked, even if they do give a wrong password.)\r
7524      * \r
7525      * I think this best serves the needs of\r
7526      * \r
7527      *  - the people who have no configuration, no keys, and just\r
7528      *    want to try repeated (username,password) pairs until they\r
7529      *    type both correctly\r
7530      * \r
7531      *  - people who have keys and configuration but occasionally\r
7532      *    need to fall back to passwords\r
7533      * \r
7534      *  - people with a key held in Pageant, who might not have\r
7535      *    logged in to a particular machine before; so they want to\r
7536      *    type a username, and then _either_ their key will be\r
7537      *    accepted, _or_ they will type a password. If they mistype\r
7538      *    the username they will want to be able to get back and\r
7539      *    retype it!\r
7540      */\r
7541     s->username[0] = '\0';\r
7542     s->got_username = FALSE;\r
7543     while (!s->we_are_in) {\r
7544         /*\r
7545          * Get a username.\r
7546          */\r
7547         if (s->got_username && !ssh->cfg.change_username) {\r
7548             /*\r
7549              * We got a username last time round this loop, and\r
7550              * with change_username turned off we don't try to get\r
7551              * it again.\r
7552              */\r
7553         } else if (!get_remote_username(&ssh->cfg, s->username,\r
7554                                         sizeof(s->username))) {\r
7555             int ret; /* need not be kept over crReturn */\r
7556             s->cur_prompt = new_prompts(ssh->frontend);\r
7557             s->cur_prompt->to_server = TRUE;\r
7558             s->cur_prompt->name = dupstr("SSH login name");\r
7559             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE,\r
7560                        lenof(s->username)); \r
7561             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
7562             while (ret < 0) {\r
7563                 ssh->send_ok = 1;\r
7564                 crWaitUntilV(!pktin);\r
7565                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
7566                 ssh->send_ok = 0;\r
7567             }\r
7568             if (!ret) {\r
7569                 /*\r
7570                  * get_userpass_input() failed to get a username.\r
7571                  * Terminate.\r
7572                  */\r
7573                 free_prompts(s->cur_prompt);\r
7574                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
7575                 crStopV;\r
7576             }\r
7577             memcpy(s->username, s->cur_prompt->prompts[0]->result,\r
7578                    lenof(s->username));\r
7579             free_prompts(s->cur_prompt);\r
7580         } else {\r
7581             char *stuff;\r
7582             if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {\r
7583                 stuff = dupprintf("Using username \"%s\".\r\n", s->username);\r
7584                 c_write_str(ssh, stuff);\r
7585                 sfree(stuff);\r
7586             }\r
7587         }\r
7588         s->got_username = TRUE;\r
7590         /*\r
7591          * Send an authentication request using method "none": (a)\r
7592          * just in case it succeeds, and (b) so that we know what\r
7593          * authentication methods we can usefully try next.\r
7594          */\r
7595         ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
7597         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
7598         ssh2_pkt_addstring(s->pktout, s->username);\r
7599         ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */\r
7600         ssh2_pkt_addstring(s->pktout, "none");    /* method */\r
7601         ssh2_pkt_send(ssh, s->pktout);\r
7602         s->type = AUTH_TYPE_NONE;\r
7603         s->gotit = FALSE;\r
7604         s->we_are_in = FALSE;\r
7606         s->tried_pubkey_config = FALSE;\r
7607         s->kbd_inter_refused = FALSE;\r
7609         /* Reset agent request state. */\r
7610         s->done_agent = FALSE;\r
7611         if (s->agent_response) {\r
7612             if (s->pkblob_in_agent) {\r
7613                 s->agentp = s->pkblob_in_agent;\r
7614             } else {\r
7615                 s->agentp = s->agent_response + 5 + 4;\r
7616                 s->keyi = 0;\r
7617             }\r
7618         }\r
7620         while (1) {\r
7621             char *methods = NULL;\r
7622             int methlen = 0;\r
7624             /*\r
7625              * Wait for the result of the last authentication request.\r
7626              */\r
7627             if (!s->gotit)\r
7628                 crWaitUntilV(pktin);\r
7629             /*\r
7630              * Now is a convenient point to spew any banner material\r
7631              * that we've accumulated. (This should ensure that when\r
7632              * we exit the auth loop, we haven't any left to deal\r
7633              * with.)\r
7634              */\r
7635             {\r
7636                 int size = bufchain_size(&ssh->banner);\r
7637                 /*\r
7638                  * Don't show the banner if we're operating in\r
7639                  * non-verbose non-interactive mode. (It's probably\r
7640                  * a script, which means nobody will read the\r
7641                  * banner _anyway_, and moreover the printing of\r
7642                  * the banner will screw up processing on the\r
7643                  * output of (say) plink.)\r
7644                  */\r
7645                 if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {\r
7646                     char *banner = snewn(size, char);\r
7647                     bufchain_fetch(&ssh->banner, banner, size);\r
7648                     c_write_untrusted(ssh, banner, size);\r
7649                     sfree(banner);\r
7650                 }\r
7651                 bufchain_clear(&ssh->banner);\r
7652             }\r
7653             if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {\r
7654                 logevent("Access granted");\r
7655                 s->we_are_in = s->userauth_success = TRUE;\r
7656                 break;\r
7657             }\r
7659             if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) {\r
7660                 bombout(("Strange packet received during authentication: "\r
7661                          "type %d", pktin->type));\r
7662                 crStopV;\r
7663             }\r
7665             s->gotit = FALSE;\r
7667             /*\r
7668              * OK, we're now sitting on a USERAUTH_FAILURE message, so\r
7669              * we can look at the string in it and know what we can\r
7670              * helpfully try next.\r
7671              */\r
7672             if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {\r
7673                 ssh_pkt_getstring(pktin, &methods, &methlen);\r
7674                 if (!ssh2_pkt_getbool(pktin)) {\r
7675                     /*\r
7676                      * We have received an unequivocal Access\r
7677                      * Denied. This can translate to a variety of\r
7678                      * messages, or no message at all.\r
7679                      *\r
7680                      * For forms of authentication which are attempted\r
7681                      * implicitly, by which I mean without printing\r
7682                      * anything in the window indicating that we're\r
7683                      * trying them, we should never print 'Access\r
7684                      * denied'.\r
7685                      *\r
7686                      * If we do print a message saying that we're\r
7687                      * attempting some kind of authentication, it's OK\r
7688                      * to print a followup message saying it failed -\r
7689                      * but the message may sometimes be more specific\r
7690                      * than simply 'Access denied'.\r
7691                      *\r
7692                      * Additionally, if we'd just tried password\r
7693                      * authentication, we should break out of this\r
7694                      * whole loop so as to go back to the username\r
7695                      * prompt (iff we're configured to allow\r
7696                      * username change attempts).\r
7697                      */\r
7698                     if (s->type == AUTH_TYPE_NONE) {\r
7699                         /* do nothing */\r
7700                     } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||\r
7701                                s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {\r
7702                         if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)\r
7703                             c_write_str(ssh, "Server refused our key\r\n");\r
7704                         logevent("Server refused our key");\r
7705                     } else if (s->type == AUTH_TYPE_PUBLICKEY) {\r
7706                         /* This _shouldn't_ happen except by a\r
7707                          * protocol bug causing client and server to\r
7708                          * disagree on what is a correct signature. */\r
7709                         c_write_str(ssh, "Server refused public-key signature"\r
7710                                     " despite accepting key!\r\n");\r
7711                         logevent("Server refused public-key signature"\r
7712                                  " despite accepting key!");\r
7713                     } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {\r
7714                         /* quiet, so no c_write */\r
7715                         logevent("Server refused keyboard-interactive authentication");\r
7716                     } else if (s->type==AUTH_TYPE_GSSAPI) {\r
7717                         /* always quiet, so no c_write */\r
7718                         /* also, the code down in the GSSAPI block has\r
7719                          * already logged this in the Event Log */\r
7720                     } else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) {\r
7721                         logevent("Keyboard-interactive authentication failed");\r
7722                         c_write_str(ssh, "Access denied\r\n");\r
7723                     } else {\r
7724                         assert(s->type == AUTH_TYPE_PASSWORD);\r
7725                         logevent("Password authentication failed");\r
7726                         c_write_str(ssh, "Access denied\r\n");\r
7728                         if (ssh->cfg.change_username) {\r
7729                             /* XXX perhaps we should allow\r
7730                              * keyboard-interactive to do this too? */\r
7731                             s->we_are_in = FALSE;\r
7732                             break;\r
7733                         }\r
7734                     }\r
7735                 } else {\r
7736                     c_write_str(ssh, "Further authentication required\r\n");\r
7737                     logevent("Further authentication required");\r
7738                 }\r
7740                 s->can_pubkey =\r
7741                     in_commasep_string("publickey", methods, methlen);\r
7742                 s->can_passwd =\r
7743                     in_commasep_string("password", methods, methlen);\r
7744                 s->can_keyb_inter = ssh->cfg.try_ki_auth &&\r
7745                     in_commasep_string("keyboard-interactive", methods, methlen);\r
7746 #ifndef NO_GSSAPI\r
7747                 if (!ssh->gsslibs)\r
7748                     ssh->gsslibs = ssh_gss_setup(&ssh->cfg);\r
7749                 s->can_gssapi = ssh->cfg.try_gssapi_auth &&\r
7750                     in_commasep_string("gssapi-with-mic", methods, methlen) &&\r
7751                     ssh->gsslibs->nlibraries > 0;\r
7752 #endif\r
7753             }\r
7755             ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
7757             if (s->can_pubkey && !s->done_agent && s->nkeys) {\r
7759                 /*\r
7760                  * Attempt public-key authentication using a key from Pageant.\r
7761                  */\r
7763                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
7765                 logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
7767                 /* Unpack key from agent response */\r
7768                 s->pklen = GET_32BIT(s->agentp);\r
7769                 s->agentp += 4;\r
7770                 s->pkblob = (char *)s->agentp;\r
7771                 s->agentp += s->pklen;\r
7772                 s->alglen = GET_32BIT(s->pkblob);\r
7773                 s->alg = s->pkblob + 4;\r
7774                 s->commentlen = GET_32BIT(s->agentp);\r
7775                 s->agentp += 4;\r
7776                 s->commentp = (char *)s->agentp;\r
7777                 s->agentp += s->commentlen;\r
7778                 /* s->agentp now points at next key, if any */\r
7780                 /* See if server will accept it */\r
7781                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
7782                 ssh2_pkt_addstring(s->pktout, s->username);\r
7783                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
7784                                                     /* service requested */\r
7785                 ssh2_pkt_addstring(s->pktout, "publickey");\r
7786                                                     /* method */\r
7787                 ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */\r
7788                 ssh2_pkt_addstring_start(s->pktout);\r
7789                 ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
7790                 ssh2_pkt_addstring_start(s->pktout);\r
7791                 ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
7792                 ssh2_pkt_send(ssh, s->pktout);\r
7793                 s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;\r
7795                 crWaitUntilV(pktin);\r
7796                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
7798                     /* Offer of key refused. */\r
7799                     s->gotit = TRUE;\r
7801                 } else {\r
7802                     \r
7803                     void *vret;\r
7805                     if (flags & FLAG_VERBOSE) {\r
7806                         c_write_str(ssh, "Authenticating with "\r
7807                                     "public key \"");\r
7808                         c_write(ssh, s->commentp, s->commentlen);\r
7809                         c_write_str(ssh, "\" from agent\r\n");\r
7810                     }\r
7812                     /*\r
7813                      * Server is willing to accept the key.\r
7814                      * Construct a SIGN_REQUEST.\r
7815                      */\r
7816                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
7817                     ssh2_pkt_addstring(s->pktout, s->username);\r
7818                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
7819                                                         /* service requested */\r
7820                     ssh2_pkt_addstring(s->pktout, "publickey");\r
7821                                                         /* method */\r
7822                     ssh2_pkt_addbool(s->pktout, TRUE);  /* signature included */\r
7823                     ssh2_pkt_addstring_start(s->pktout);\r
7824                     ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
7825                     ssh2_pkt_addstring_start(s->pktout);\r
7826                     ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
7828                     /* Ask agent for signature. */\r
7829                     s->siglen = s->pktout->length - 5 + 4 +\r
7830                         ssh->v2_session_id_len;\r
7831                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
7832                         s->siglen -= 4;\r
7833                     s->len = 1;       /* message type */\r
7834                     s->len += 4 + s->pklen;     /* key blob */\r
7835                     s->len += 4 + s->siglen;    /* data to sign */\r
7836                     s->len += 4;      /* flags */\r
7837                     s->agentreq = snewn(4 + s->len, char);\r
7838                     PUT_32BIT(s->agentreq, s->len);\r
7839                     s->q = s->agentreq + 4;\r
7840                     *s->q++ = SSH2_AGENTC_SIGN_REQUEST;\r
7841                     PUT_32BIT(s->q, s->pklen);\r
7842                     s->q += 4;\r
7843                     memcpy(s->q, s->pkblob, s->pklen);\r
7844                     s->q += s->pklen;\r
7845                     PUT_32BIT(s->q, s->siglen);\r
7846                     s->q += 4;\r
7847                     /* Now the data to be signed... */\r
7848                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
7849                         PUT_32BIT(s->q, ssh->v2_session_id_len);\r
7850                         s->q += 4;\r
7851                     }\r
7852                     memcpy(s->q, ssh->v2_session_id,\r
7853                            ssh->v2_session_id_len);\r
7854                     s->q += ssh->v2_session_id_len;\r
7855                     memcpy(s->q, s->pktout->data + 5,\r
7856                            s->pktout->length - 5);\r
7857                     s->q += s->pktout->length - 5;\r
7858                     /* And finally the (zero) flags word. */\r
7859                     PUT_32BIT(s->q, 0);\r
7860                     if (!agent_query(s->agentreq, s->len + 4,\r
7861                                      &vret, &s->retlen,\r
7862                                      ssh_agent_callback, ssh)) {\r
7863                         do {\r
7864                             crReturnV;\r
7865                             if (pktin) {\r
7866                                 bombout(("Unexpected data from server"\r
7867                                          " while waiting for agent"\r
7868                                          " response"));\r
7869                                 crStopV;\r
7870                             }\r
7871                         } while (pktin || inlen > 0);\r
7872                         vret = ssh->agent_response;\r
7873                         s->retlen = ssh->agent_response_len;\r
7874                     }\r
7875                     s->ret = vret;\r
7876                     sfree(s->agentreq);\r
7877                     if (s->ret) {\r
7878                         if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) {\r
7879                             logevent("Sending Pageant's response");\r
7880                             ssh2_add_sigblob(ssh, s->pktout,\r
7881                                              s->pkblob, s->pklen,\r
7882                                              s->ret + 9,\r
7883                                              GET_32BIT(s->ret + 5));\r
7884                             ssh2_pkt_send(ssh, s->pktout);\r
7885                             s->type = AUTH_TYPE_PUBLICKEY;\r
7886                         } else {\r
7887                             /* FIXME: less drastic response */\r
7888                             bombout(("Pageant failed to answer challenge"));\r
7889                             crStopV;\r
7890                         }\r
7891                     }\r
7892                 }\r
7894                 /* Do we have any keys left to try? */\r
7895                 if (s->pkblob_in_agent) {\r
7896                     s->done_agent = TRUE;\r
7897                     s->tried_pubkey_config = TRUE;\r
7898                 } else {\r
7899                     s->keyi++;\r
7900                     if (s->keyi >= s->nkeys)\r
7901                         s->done_agent = TRUE;\r
7902                 }\r
7904             } else if (s->can_pubkey && s->publickey_blob &&\r
7905                        !s->tried_pubkey_config) {\r
7907                 struct ssh2_userkey *key;   /* not live over crReturn */\r
7908                 char *passphrase;           /* not live over crReturn */\r
7910                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
7912                 s->tried_pubkey_config = TRUE;\r
7914                 /*\r
7915                  * Try the public key supplied in the configuration.\r
7916                  *\r
7917                  * First, offer the public blob to see if the server is\r
7918                  * willing to accept it.\r
7919                  */\r
7920                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
7921                 ssh2_pkt_addstring(s->pktout, s->username);\r
7922                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
7923                                                 /* service requested */\r
7924                 ssh2_pkt_addstring(s->pktout, "publickey");     /* method */\r
7925                 ssh2_pkt_addbool(s->pktout, FALSE);\r
7926                                                 /* no signature included */\r
7927                 ssh2_pkt_addstring(s->pktout, s->publickey_algorithm);\r
7928                 ssh2_pkt_addstring_start(s->pktout);\r
7929                 ssh2_pkt_addstring_data(s->pktout,\r
7930                                         (char *)s->publickey_blob,\r
7931                                         s->publickey_bloblen);\r
7932                 ssh2_pkt_send(ssh, s->pktout);\r
7933                 logevent("Offered public key");\r
7935                 crWaitUntilV(pktin);\r
7936                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
7937                     /* Key refused. Give up. */\r
7938                     s->gotit = TRUE; /* reconsider message next loop */\r
7939                     s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;\r
7940                     continue; /* process this new message */\r
7941                 }\r
7942                 logevent("Offer of public key accepted");\r
7944                 /*\r
7945                  * Actually attempt a serious authentication using\r
7946                  * the key.\r
7947                  */\r
7948                 if (flags & FLAG_VERBOSE) {\r
7949                     c_write_str(ssh, "Authenticating with public key \"");\r
7950                     c_write_str(ssh, s->publickey_comment);\r
7951                     c_write_str(ssh, "\"\r\n");\r
7952                 }\r
7953                 key = NULL;\r
7954                 while (!key) {\r
7955                     const char *error;  /* not live over crReturn */\r
7956                     if (s->publickey_encrypted) {\r
7957                         /*\r
7958                          * Get a passphrase from the user.\r
7959                          */\r
7960                         int ret; /* need not be kept over crReturn */\r
7961                         s->cur_prompt = new_prompts(ssh->frontend);\r
7962                         s->cur_prompt->to_server = FALSE;\r
7963                         s->cur_prompt->name = dupstr("SSH key passphrase");\r
7964                         add_prompt(s->cur_prompt,\r
7965                                    dupprintf("Passphrase for key \"%.100s\": ",\r
7966                                              s->publickey_comment),\r
7967                                    FALSE, SSH_MAX_PASSWORD_LEN);\r
7968                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
7969                         while (ret < 0) {\r
7970                             ssh->send_ok = 1;\r
7971                             crWaitUntilV(!pktin);\r
7972                             ret = get_userpass_input(s->cur_prompt,\r
7973                                                      in, inlen);\r
7974                             ssh->send_ok = 0;\r
7975                         }\r
7976                         if (!ret) {\r
7977                             /* Failed to get a passphrase. Terminate. */\r
7978                             free_prompts(s->cur_prompt);\r
7979                             ssh_disconnect(ssh, NULL,\r
7980                                            "Unable to authenticate",\r
7981                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
7982                                            TRUE);\r
7983                             crStopV;\r
7984                         }\r
7985                         passphrase =\r
7986                             dupstr(s->cur_prompt->prompts[0]->result);\r
7987                         free_prompts(s->cur_prompt);\r
7988                     } else {\r
7989                         passphrase = NULL; /* no passphrase needed */\r
7990                     }\r
7992                     /*\r
7993                      * Try decrypting the key.\r
7994                      */\r
7995                     key = ssh2_load_userkey(&ssh->cfg.keyfile, passphrase,\r
7996                                             &error);\r
7997                     if (passphrase) {\r
7998                         /* burn the evidence */\r
7999                         memset(passphrase, 0, strlen(passphrase));\r
8000                         sfree(passphrase);\r
8001                     }\r
8002                     if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {\r
8003                         if (passphrase &&\r
8004                             (key == SSH2_WRONG_PASSPHRASE)) {\r
8005                             c_write_str(ssh, "Wrong passphrase\r\n");\r
8006                             key = NULL;\r
8007                             /* and loop again */\r
8008                         } else {\r
8009                             c_write_str(ssh, "Unable to load private key (");\r
8010                             c_write_str(ssh, error);\r
8011                             c_write_str(ssh, ")\r\n");\r
8012                             key = NULL;\r
8013                             break; /* try something else */\r
8014                         }\r
8015                     }\r
8016                 }\r
8018                 if (key) {\r
8019                     unsigned char *pkblob, *sigblob, *sigdata;\r
8020                     int pkblob_len, sigblob_len, sigdata_len;\r
8021                     int p;\r
8023                     /*\r
8024                      * We have loaded the private key and the server\r
8025                      * has announced that it's willing to accept it.\r
8026                      * Hallelujah. Generate a signature and send it.\r
8027                      */\r
8028                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8029                     ssh2_pkt_addstring(s->pktout, s->username);\r
8030                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8031                                                     /* service requested */\r
8032                     ssh2_pkt_addstring(s->pktout, "publickey");\r
8033                                                     /* method */\r
8034                     ssh2_pkt_addbool(s->pktout, TRUE);\r
8035                                                     /* signature follows */\r
8036                     ssh2_pkt_addstring(s->pktout, key->alg->name);\r
8037                     pkblob = key->alg->public_blob(key->data,\r
8038                                                    &pkblob_len);\r
8039                     ssh2_pkt_addstring_start(s->pktout);\r
8040                     ssh2_pkt_addstring_data(s->pktout, (char *)pkblob,\r
8041                                             pkblob_len);\r
8043                     /*\r
8044                      * The data to be signed is:\r
8045                      *\r
8046                      *   string  session-id\r
8047                      *\r
8048                      * followed by everything so far placed in the\r
8049                      * outgoing packet.\r
8050                      */\r
8051                     sigdata_len = s->pktout->length - 5 + 4 +\r
8052                         ssh->v2_session_id_len;\r
8053                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
8054                         sigdata_len -= 4;\r
8055                     sigdata = snewn(sigdata_len, unsigned char);\r
8056                     p = 0;\r
8057                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
8058                         PUT_32BIT(sigdata+p, ssh->v2_session_id_len);\r
8059                         p += 4;\r
8060                     }\r
8061                     memcpy(sigdata+p, ssh->v2_session_id,\r
8062                            ssh->v2_session_id_len);\r
8063                     p += ssh->v2_session_id_len;\r
8064                     memcpy(sigdata+p, s->pktout->data + 5,\r
8065                            s->pktout->length - 5);\r
8066                     p += s->pktout->length - 5;\r
8067                     assert(p == sigdata_len);\r
8068                     sigblob = key->alg->sign(key->data, (char *)sigdata,\r
8069                                              sigdata_len, &sigblob_len);\r
8070                     ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,\r
8071                                      sigblob, sigblob_len);\r
8072                     sfree(pkblob);\r
8073                     sfree(sigblob);\r
8074                     sfree(sigdata);\r
8076                     ssh2_pkt_send(ssh, s->pktout);\r
8077                     logevent("Sent public key signature");\r
8078                     s->type = AUTH_TYPE_PUBLICKEY;\r
8079                     key->alg->freekey(key->data);\r
8080                 }\r
8082 #ifndef NO_GSSAPI\r
8083             } else if (s->can_gssapi && !s->tried_gssapi) {\r
8085                 /* GSSAPI Authentication */\r
8087                 int micoffset, len;\r
8088                 char *data;\r
8089                 Ssh_gss_buf mic;\r
8090                 s->type = AUTH_TYPE_GSSAPI;\r
8091                 s->tried_gssapi = TRUE;\r
8092                 s->gotit = TRUE;\r
8093                 ssh->pkt_actx = SSH2_PKTCTX_GSSAPI;\r
8095                 /*\r
8096                  * Pick the highest GSS library on the preference\r
8097                  * list.\r
8098                  */\r
8099                 {\r
8100                     int i, j;\r
8101                     s->gsslib = NULL;\r
8102                     for (i = 0; i < ngsslibs; i++) {\r
8103                         int want_id = ssh->cfg.ssh_gsslist[i];\r
8104                         for (j = 0; j < ssh->gsslibs->nlibraries; j++)\r
8105                             if (ssh->gsslibs->libraries[j].id == want_id) {\r
8106                                 s->gsslib = &ssh->gsslibs->libraries[j];\r
8107                                 goto got_gsslib;   /* double break */\r
8108                             }\r
8109                     }\r
8110                     got_gsslib:\r
8111                     /*\r
8112                      * We always expect to have found something in\r
8113                      * the above loop: we only came here if there\r
8114                      * was at least one viable GSS library, and the\r
8115                      * preference list should always mention\r
8116                      * everything and only change the order.\r
8117                      */\r
8118                     assert(s->gsslib);\r
8119                 }\r
8121                 if (s->gsslib->gsslogmsg)\r
8122                     logevent(s->gsslib->gsslogmsg);\r
8124                 /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */\r
8125                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8126                 ssh2_pkt_addstring(s->pktout, s->username);\r
8127                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8128                 ssh2_pkt_addstring(s->pktout, "gssapi-with-mic");\r
8129                 logevent("Attempting GSSAPI authentication");\r
8131                 /* add mechanism info */\r
8132                 s->gsslib->indicate_mech(s->gsslib, &s->gss_buf);\r
8134                 /* number of GSSAPI mechanisms */\r
8135                 ssh2_pkt_adduint32(s->pktout,1);\r
8137                 /* length of OID + 2 */\r
8138                 ssh2_pkt_adduint32(s->pktout, s->gss_buf.length + 2);\r
8139                 ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);\r
8141                 /* length of OID */\r
8142                 ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.length);\r
8144                 ssh_pkt_adddata(s->pktout, s->gss_buf.value,\r
8145                                 s->gss_buf.length);\r
8146                 ssh2_pkt_send(ssh, s->pktout);\r
8147                 crWaitUntilV(pktin);\r
8148                 if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {\r
8149                     logevent("GSSAPI authentication request refused");\r
8150                     continue;\r
8151                 }\r
8153                 /* check returned packet ... */\r
8155                 ssh_pkt_getstring(pktin, &data, &len);\r
8156                 s->gss_rcvtok.value = data;\r
8157                 s->gss_rcvtok.length = len;\r
8158                 if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||\r
8159                     ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||\r
8160                     ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||\r
8161                     memcmp((char *)s->gss_rcvtok.value + 2,\r
8162                            s->gss_buf.value,s->gss_buf.length) ) {\r
8163                     logevent("GSSAPI authentication - wrong response from server");\r
8164                     continue;\r
8165                 }\r
8167                 /* now start running */\r
8168                 s->gss_stat = s->gsslib->import_name(s->gsslib,\r
8169                                                      ssh->fullhostname,\r
8170                                                      &s->gss_srv_name);\r
8171                 if (s->gss_stat != SSH_GSS_OK) {\r
8172                     if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)\r
8173                         logevent("GSSAPI import name failed - Bad service name");\r
8174                     else\r
8175                         logevent("GSSAPI import name failed");\r
8176                     continue;\r
8177                 }\r
8179                 /* fetch TGT into GSS engine */\r
8180                 s->gss_stat = s->gsslib->acquire_cred(s->gsslib, &s->gss_ctx);\r
8182                 if (s->gss_stat != SSH_GSS_OK) {\r
8183                     logevent("GSSAPI authentication failed to get credentials");\r
8184                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8185                     continue;\r
8186                 }\r
8188                 /* initial tokens are empty */\r
8189                 SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);\r
8190                 SSH_GSS_CLEAR_BUF(&s->gss_sndtok);\r
8192                 /* now enter the loop */\r
8193                 do {\r
8194                     s->gss_stat = s->gsslib->init_sec_context\r
8195                         (s->gsslib,\r
8196                          &s->gss_ctx,\r
8197                          s->gss_srv_name,\r
8198                          ssh->cfg.gssapifwd,\r
8199                          &s->gss_rcvtok,\r
8200                          &s->gss_sndtok);\r
8202                     if (s->gss_stat!=SSH_GSS_S_COMPLETE &&\r
8203                         s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) {\r
8204                         logevent("GSSAPI authentication initialisation failed");\r
8206                         if (s->gsslib->display_status(s->gsslib, s->gss_ctx,\r
8207                                                       &s->gss_buf) == SSH_GSS_OK) {\r
8208                             logevent(s->gss_buf.value);\r
8209                             sfree(s->gss_buf.value);\r
8210                         }\r
8212                         break;\r
8213                     }\r
8214                     logevent("GSSAPI authentication initialised");\r
8216                     /* Client and server now exchange tokens until GSSAPI\r
8217                      * no longer says CONTINUE_NEEDED */\r
8219                     if (s->gss_sndtok.length != 0) {\r
8220                         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);\r
8221                         ssh_pkt_addstring_start(s->pktout);\r
8222                         ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.value,s->gss_sndtok.length);\r
8223                         ssh2_pkt_send(ssh, s->pktout);\r
8224                         s->gsslib->free_tok(s->gsslib, &s->gss_sndtok);\r
8225                     }\r
8227                     if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {\r
8228                         crWaitUntilV(pktin);\r
8229                         if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {\r
8230                             logevent("GSSAPI authentication - bad server response");\r
8231                             s->gss_stat = SSH_GSS_FAILURE;\r
8232                             break;\r
8233                         }\r
8234                         ssh_pkt_getstring(pktin, &data, &len);\r
8235                         s->gss_rcvtok.value = data;\r
8236                         s->gss_rcvtok.length = len;\r
8237                     }\r
8238                 } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);\r
8240                 if (s->gss_stat != SSH_GSS_OK) {\r
8241                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8242                     s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
8243                     continue;\r
8244                 }\r
8245                 logevent("GSSAPI authentication loop finished OK");\r
8247                 /* Now send the MIC */\r
8249                 s->pktout = ssh2_pkt_init(0);\r
8250                 micoffset = s->pktout->length;\r
8251                 ssh_pkt_addstring_start(s->pktout);\r
8252                 ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len);\r
8253                 ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST);\r
8254                 ssh_pkt_addstring(s->pktout, s->username);\r
8255                 ssh_pkt_addstring(s->pktout, "ssh-connection");\r
8256                 ssh_pkt_addstring(s->pktout, "gssapi-with-mic");\r
8258                 s->gss_buf.value = (char *)s->pktout->data + micoffset;\r
8259                 s->gss_buf.length = s->pktout->length - micoffset;\r
8261                 s->gsslib->get_mic(s->gsslib, s->gss_ctx, &s->gss_buf, &mic);\r
8262                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC);\r
8263                 ssh_pkt_addstring_start(s->pktout);\r
8264                 ssh_pkt_addstring_data(s->pktout, mic.value, mic.length);\r
8265                 ssh2_pkt_send(ssh, s->pktout);\r
8266                 s->gsslib->free_mic(s->gsslib, &mic);\r
8268                 s->gotit = FALSE;\r
8270                 s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
8271                 s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
8272                 continue;\r
8273 #endif\r
8274             } else if (s->can_keyb_inter && !s->kbd_inter_refused) {\r
8276                 /*\r
8277                  * Keyboard-interactive authentication.\r
8278                  */\r
8280                 s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;\r
8282                 ssh->pkt_actx = SSH2_PKTCTX_KBDINTER;\r
8284                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8285                 ssh2_pkt_addstring(s->pktout, s->username);\r
8286                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8287                                                         /* service requested */\r
8288                 ssh2_pkt_addstring(s->pktout, "keyboard-interactive");\r
8289                                                         /* method */\r
8290                 ssh2_pkt_addstring(s->pktout, "");      /* lang */\r
8291                 ssh2_pkt_addstring(s->pktout, "");      /* submethods */\r
8292                 ssh2_pkt_send(ssh, s->pktout);\r
8293                 \r
8294                 logevent("Attempting keyboard-interactive authentication");\r
8296                 crWaitUntilV(pktin);\r
8297                 if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
8298                     /* Server is not willing to do keyboard-interactive\r
8299                      * at all (or, bizarrely but legally, accepts the\r
8300                      * user without actually issuing any prompts).\r
8301                      * Give up on it entirely. */\r
8302                     s->gotit = TRUE;\r
8303                     s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;\r
8304                     s->kbd_inter_refused = TRUE; /* don't try it again */\r
8305                     continue;\r
8306                 }\r
8308                 /*\r
8309                  * Loop while the server continues to send INFO_REQUESTs.\r
8310                  */\r
8311                 while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
8313                     char *name, *inst, *lang;\r
8314                     int name_len, inst_len, lang_len;\r
8315                     int i;\r
8317                     /*\r
8318                      * We've got a fresh USERAUTH_INFO_REQUEST.\r
8319                      * Get the preamble and start building a prompt.\r
8320                      */\r
8321                     ssh_pkt_getstring(pktin, &name, &name_len);\r
8322                     ssh_pkt_getstring(pktin, &inst, &inst_len);\r
8323                     ssh_pkt_getstring(pktin, &lang, &lang_len);\r
8324                     s->cur_prompt = new_prompts(ssh->frontend);\r
8325                     s->cur_prompt->to_server = TRUE;\r
8327                     /*\r
8328                      * Get any prompt(s) from the packet.\r
8329                      */\r
8330                     s->num_prompts = ssh_pkt_getuint32(pktin);\r
8331                     for (i = 0; i < s->num_prompts; i++) {\r
8332                         char *prompt;\r
8333                         int prompt_len;\r
8334                         int echo;\r
8335                         static char noprompt[] =\r
8336                             "<server failed to send prompt>: ";\r
8338                         ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
8339                         echo = ssh2_pkt_getbool(pktin);\r
8340                         if (!prompt_len) {\r
8341                             prompt = noprompt;\r
8342                             prompt_len = lenof(noprompt)-1;\r
8343                         }\r
8344                         add_prompt(s->cur_prompt,\r
8345                                    dupprintf("%.*s", prompt_len, prompt),\r
8346                                    echo, SSH_MAX_PASSWORD_LEN);\r
8347                     }\r
8349                     if (name_len) {\r
8350                         /* FIXME: better prefix to distinguish from\r
8351                          * local prompts? */\r
8352                         s->cur_prompt->name =\r
8353                             dupprintf("SSH server: %.*s", name_len, name);\r
8354                         s->cur_prompt->name_reqd = TRUE;\r
8355                     } else {\r
8356                         s->cur_prompt->name =\r
8357                             dupstr("SSH server authentication");\r
8358                         s->cur_prompt->name_reqd = FALSE;\r
8359                     }\r
8360                     /* We add a prefix to try to make it clear that a prompt\r
8361                      * has come from the server.\r
8362                      * FIXME: ugly to print "Using..." in prompt _every_\r
8363                      * time round. Can this be done more subtly? */\r
8364                     /* Special case: for reasons best known to themselves,\r
8365                      * some servers send k-i requests with no prompts and\r
8366                      * nothing to display. Keep quiet in this case. */\r
8367                     if (s->num_prompts || name_len || inst_len) {\r
8368                         s->cur_prompt->instruction =\r
8369                             dupprintf("Using keyboard-interactive authentication.%s%.*s",\r
8370                                       inst_len ? "\n" : "", inst_len, inst);\r
8371                         s->cur_prompt->instr_reqd = TRUE;\r
8372                     } else {\r
8373                         s->cur_prompt->instr_reqd = FALSE;\r
8374                     }\r
8376                     /*\r
8377                      * Display any instructions, and get the user's\r
8378                      * response(s).\r
8379                      */\r
8380                     {\r
8381                         int ret; /* not live over crReturn */\r
8382                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8383                         while (ret < 0) {\r
8384                             ssh->send_ok = 1;\r
8385                             crWaitUntilV(!pktin);\r
8386                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8387                             ssh->send_ok = 0;\r
8388                         }\r
8389                         if (!ret) {\r
8390                             /*\r
8391                              * Failed to get responses. Terminate.\r
8392                              */\r
8393                             free_prompts(s->cur_prompt);\r
8394                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
8395                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8396                                            TRUE);\r
8397                             crStopV;\r
8398                         }\r
8399                     }\r
8401                     /*\r
8402                      * Send the response(s) to the server.\r
8403                      */\r
8404                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);\r
8405                     ssh2_pkt_adduint32(s->pktout, s->num_prompts);\r
8406                     for (i=0; i < s->num_prompts; i++) {\r
8407                         dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8408                         ssh2_pkt_addstring(s->pktout,\r
8409                                            s->cur_prompt->prompts[i]->result);\r
8410                         end_log_omission(ssh, s->pktout);\r
8411                     }\r
8412                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
8414                     /*\r
8415                      * Free the prompts structure from this iteration.\r
8416                      * If there's another, a new one will be allocated\r
8417                      * when we return to the top of this while loop.\r
8418                      */\r
8419                     free_prompts(s->cur_prompt);\r
8421                     /*\r
8422                      * Get the next packet in case it's another\r
8423                      * INFO_REQUEST.\r
8424                      */\r
8425                     crWaitUntilV(pktin);\r
8427                 }\r
8429                 /*\r
8430                  * We should have SUCCESS or FAILURE now.\r
8431                  */\r
8432                 s->gotit = TRUE;\r
8434             } else if (s->can_passwd) {\r
8436                 /*\r
8437                  * Plain old password authentication.\r
8438                  */\r
8439                 int ret; /* not live over crReturn */\r
8440                 int changereq_first_time; /* not live over crReturn */\r
8442                 ssh->pkt_actx = SSH2_PKTCTX_PASSWORD;\r
8444                 s->cur_prompt = new_prompts(ssh->frontend);\r
8445                 s->cur_prompt->to_server = TRUE;\r
8446                 s->cur_prompt->name = dupstr("SSH password");\r
8447                 add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ",\r
8448                                                     s->username,\r
8449                                                     ssh->savedhost),\r
8450                            FALSE, SSH_MAX_PASSWORD_LEN);\r
8452                 ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8453                 while (ret < 0) {\r
8454                     ssh->send_ok = 1;\r
8455                     crWaitUntilV(!pktin);\r
8456                     ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8457                     ssh->send_ok = 0;\r
8458                 }\r
8459                 if (!ret) {\r
8460                     /*\r
8461                      * Failed to get responses. Terminate.\r
8462                      */\r
8463                     free_prompts(s->cur_prompt);\r
8464                     ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
8465                                    SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8466                                    TRUE);\r
8467                     crStopV;\r
8468                 }\r
8469                 /*\r
8470                  * Squirrel away the password. (We may need it later if\r
8471                  * asked to change it.)\r
8472                  */\r
8473                 s->password = dupstr(s->cur_prompt->prompts[0]->result);\r
8474                 free_prompts(s->cur_prompt);\r
8476                 /*\r
8477                  * Send the password packet.\r
8478                  *\r
8479                  * We pad out the password packet to 256 bytes to make\r
8480                  * it harder for an attacker to find the length of the\r
8481                  * user's password.\r
8482                  *\r
8483                  * Anyone using a password longer than 256 bytes\r
8484                  * probably doesn't have much to worry about from\r
8485                  * people who find out how long their password is!\r
8486                  */\r
8487                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8488                 ssh2_pkt_addstring(s->pktout, s->username);\r
8489                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8490                                                         /* service requested */\r
8491                 ssh2_pkt_addstring(s->pktout, "password");\r
8492                 ssh2_pkt_addbool(s->pktout, FALSE);\r
8493                 dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8494                 ssh2_pkt_addstring(s->pktout, s->password);\r
8495                 end_log_omission(ssh, s->pktout);\r
8496                 ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
8497                 logevent("Sent password");\r
8498                 s->type = AUTH_TYPE_PASSWORD;\r
8500                 /*\r
8501                  * Wait for next packet, in case it's a password change\r
8502                  * request.\r
8503                  */\r
8504                 crWaitUntilV(pktin);\r
8505                 changereq_first_time = TRUE;\r
8507                 while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {\r
8509                     /* \r
8510                      * We're being asked for a new password\r
8511                      * (perhaps not for the first time).\r
8512                      * Loop until the server accepts it.\r
8513                      */\r
8515                     int got_new = FALSE; /* not live over crReturn */\r
8516                     char *prompt;   /* not live over crReturn */\r
8517                     int prompt_len; /* not live over crReturn */\r
8518                     \r
8519                     {\r
8520                         char *msg;\r
8521                         if (changereq_first_time)\r
8522                             msg = "Server requested password change";\r
8523                         else\r
8524                             msg = "Server rejected new password";\r
8525                         logevent(msg);\r
8526                         c_write_str(ssh, msg);\r
8527                         c_write_str(ssh, "\r\n");\r
8528                     }\r
8530                     ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
8532                     s->cur_prompt = new_prompts(ssh->frontend);\r
8533                     s->cur_prompt->to_server = TRUE;\r
8534                     s->cur_prompt->name = dupstr("New SSH password");\r
8535                     s->cur_prompt->instruction =\r
8536                         dupprintf("%.*s", prompt_len, prompt);\r
8537                     s->cur_prompt->instr_reqd = TRUE;\r
8538                     /*\r
8539                      * There's no explicit requirement in the protocol\r
8540                      * for the "old" passwords in the original and\r
8541                      * password-change messages to be the same, and\r
8542                      * apparently some Cisco kit supports password change\r
8543                      * by the user entering a blank password originally\r
8544                      * and the real password subsequently, so,\r
8545                      * reluctantly, we prompt for the old password again.\r
8546                      *\r
8547                      * (On the other hand, some servers don't even bother\r
8548                      * to check this field.)\r
8549                      */\r
8550                     add_prompt(s->cur_prompt,\r
8551                                dupstr("Current password (blank for previously entered password): "),\r
8552                                FALSE, SSH_MAX_PASSWORD_LEN);\r
8553                     add_prompt(s->cur_prompt, dupstr("Enter new password: "),\r
8554                                FALSE, SSH_MAX_PASSWORD_LEN);\r
8555                     add_prompt(s->cur_prompt, dupstr("Confirm new password: "),\r
8556                                FALSE, SSH_MAX_PASSWORD_LEN);\r
8558                     /*\r
8559                      * Loop until the user manages to enter the same\r
8560                      * password twice.\r
8561                      */\r
8562                     while (!got_new) {\r
8564                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
8565                         while (ret < 0) {\r
8566                             ssh->send_ok = 1;\r
8567                             crWaitUntilV(!pktin);\r
8568                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
8569                             ssh->send_ok = 0;\r
8570                         }\r
8571                         if (!ret) {\r
8572                             /*\r
8573                              * Failed to get responses. Terminate.\r
8574                              */\r
8575                             /* burn the evidence */\r
8576                             free_prompts(s->cur_prompt);\r
8577                             memset(s->password, 0, strlen(s->password));\r
8578                             sfree(s->password);\r
8579                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
8580                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
8581                                            TRUE);\r
8582                             crStopV;\r
8583                         }\r
8585                         /*\r
8586                          * If the user specified a new original password\r
8587                          * (IYSWIM), overwrite any previously specified\r
8588                          * one.\r
8589                          * (A side effect is that the user doesn't have to\r
8590                          * re-enter it if they louse up the new password.)\r
8591                          */\r
8592                         if (s->cur_prompt->prompts[0]->result[0]) {\r
8593                             memset(s->password, 0, strlen(s->password));\r
8594                                 /* burn the evidence */\r
8595                             sfree(s->password);\r
8596                             s->password =\r
8597                                 dupstr(s->cur_prompt->prompts[0]->result);\r
8598                         }\r
8600                         /*\r
8601                          * Check the two new passwords match.\r
8602                          */\r
8603                         got_new = (strcmp(s->cur_prompt->prompts[1]->result,\r
8604                                           s->cur_prompt->prompts[2]->result)\r
8605                                    == 0);\r
8606                         if (!got_new)\r
8607                             /* They don't. Silly user. */\r
8608                             c_write_str(ssh, "Passwords do not match\r\n");\r
8610                     }\r
8612                     /*\r
8613                      * Send the new password (along with the old one).\r
8614                      * (see above for padding rationale)\r
8615                      */\r
8616                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
8617                     ssh2_pkt_addstring(s->pktout, s->username);\r
8618                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
8619                                                         /* service requested */\r
8620                     ssh2_pkt_addstring(s->pktout, "password");\r
8621                     ssh2_pkt_addbool(s->pktout, TRUE);\r
8622                     dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8623                     ssh2_pkt_addstring(s->pktout, s->password);\r
8624                     ssh2_pkt_addstring(s->pktout,\r
8625                                        s->cur_prompt->prompts[1]->result);\r
8626                     free_prompts(s->cur_prompt);\r
8627                     end_log_omission(ssh, s->pktout);\r
8628                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
8629                     logevent("Sent new password");\r
8630                     \r
8631                     /*\r
8632                      * Now see what the server has to say about it.\r
8633                      * (If it's CHANGEREQ again, it's not happy with the\r
8634                      * new password.)\r
8635                      */\r
8636                     crWaitUntilV(pktin);\r
8637                     changereq_first_time = FALSE;\r
8639                 }\r
8641                 /*\r
8642                  * We need to reexamine the current pktin at the top\r
8643                  * of the loop. Either:\r
8644                  *  - we weren't asked to change password at all, in\r
8645                  *    which case it's a SUCCESS or FAILURE with the\r
8646                  *    usual meaning\r
8647                  *  - we sent a new password, and the server was\r
8648                  *    either OK with it (SUCCESS or FAILURE w/partial\r
8649                  *    success) or unhappy with the _old_ password\r
8650                  *    (FAILURE w/o partial success)\r
8651                  * In any of these cases, we go back to the top of\r
8652                  * the loop and start again.\r
8653                  */\r
8654                 s->gotit = TRUE;\r
8656                 /*\r
8657                  * We don't need the old password any more, in any\r
8658                  * case. Burn the evidence.\r
8659                  */\r
8660                 memset(s->password, 0, strlen(s->password));\r
8661                 sfree(s->password);\r
8663             } else {\r
8664                 char *str = dupprintf("No supported authentication methods available"\r
8665                                       " (server sent: %.*s)",\r
8666                                       methlen, methods);\r
8668                 ssh_disconnect(ssh, str,\r
8669                                "No supported authentication methods available",\r
8670                                SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,\r
8671                                FALSE);\r
8672                 sfree(str);\r
8674                 crStopV;\r
8676             }\r
8678         }\r
8679     }\r
8680     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;\r
8682     /* Clear up various bits and pieces from authentication. */\r
8683     if (s->publickey_blob) {\r
8684         sfree(s->publickey_blob);\r
8685         sfree(s->publickey_comment);\r
8686     }\r
8687     if (s->agent_response)\r
8688         sfree(s->agent_response);\r
8690     if (s->userauth_success) {\r
8691         /*\r
8692          * We've just received USERAUTH_SUCCESS, and we haven't sent any\r
8693          * packets since. Signal the transport layer to consider enacting\r
8694          * delayed compression.\r
8695          *\r
8696          * (Relying on we_are_in is not sufficient, as\r
8697          * draft-miller-secsh-compression-delayed is quite clear that it\r
8698          * triggers on USERAUTH_SUCCESS specifically, and we_are_in can\r
8699          * become set for other reasons.)\r
8700          */\r
8701         do_ssh2_transport(ssh, "enabling delayed compression", -2, NULL);\r
8702     }\r
8704     /*\r
8705      * Now the connection protocol has started, one way or another.\r
8706      */\r
8708     ssh->channels = newtree234(ssh_channelcmp);\r
8710     /*\r
8711      * Set up handlers for some connection protocol messages, so we\r
8712      * don't have to handle them repeatedly in this coroutine.\r
8713      */\r
8714     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] =\r
8715         ssh2_msg_channel_window_adjust;\r
8716     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] =\r
8717         ssh2_msg_global_request;\r
8719     /*\r
8720      * Create the main session channel.\r
8721      */\r
8722     if (ssh->cfg.ssh_no_shell) {\r
8723         ssh->mainchan = NULL;\r
8724     } else if (*ssh->cfg.ssh_nc_host) {\r
8725         /*\r
8726          * Just start a direct-tcpip channel and use it as the main\r
8727          * channel.\r
8728          */\r
8729         ssh->mainchan = snew(struct ssh_channel);\r
8730         ssh->mainchan->ssh = ssh;\r
8731         ssh2_channel_init(ssh->mainchan);\r
8732         logeventf(ssh,\r
8733                   "Opening direct-tcpip channel to %s:%d in place of session",\r
8734                   ssh->cfg.ssh_nc_host, ssh->cfg.ssh_nc_port);\r
8735         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);\r
8736         ssh2_pkt_addstring(s->pktout, "direct-tcpip");\r
8737         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);\r
8738         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */\r
8739         ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
8740         ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host);\r
8741         ssh2_pkt_adduint32(s->pktout, ssh->cfg.ssh_nc_port);\r
8742         /*\r
8743          * There's nothing meaningful to put in the originator\r
8744          * fields, but some servers insist on syntactically correct\r
8745          * information.\r
8746          */\r
8747         ssh2_pkt_addstring(s->pktout, "0.0.0.0");\r
8748         ssh2_pkt_adduint32(s->pktout, 0);\r
8749         ssh2_pkt_send(ssh, s->pktout);\r
8751         crWaitUntilV(pktin);\r
8752         if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {\r
8753             bombout(("Server refused to open a direct-tcpip channel"));\r
8754             crStopV;\r
8755             /* FIXME: error data comes back in FAILURE packet */\r
8756         }\r
8757         if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {\r
8758             bombout(("Server's channel confirmation cited wrong channel"));\r
8759             crStopV;\r
8760         }\r
8761         ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);\r
8762         ssh->mainchan->halfopen = FALSE;\r
8763         ssh->mainchan->type = CHAN_MAINSESSION;\r
8764         ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
8765         ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
8766         add234(ssh->channels, ssh->mainchan);\r
8767         update_specials_menu(ssh->frontend);\r
8768         logevent("Opened direct-tcpip channel");\r
8769         ssh->ncmode = TRUE;\r
8770     } else {\r
8771         ssh->mainchan = snew(struct ssh_channel);\r
8772         ssh->mainchan->ssh = ssh;\r
8773         ssh2_channel_init(ssh->mainchan);\r
8774         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);\r
8775         ssh2_pkt_addstring(s->pktout, "session");\r
8776         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);\r
8777         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */\r
8778         ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT);    /* our max pkt size */\r
8779         ssh2_pkt_send(ssh, s->pktout);\r
8780         crWaitUntilV(pktin);\r
8781         if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {\r
8782             bombout(("Server refused to open a session"));\r
8783             crStopV;\r
8784             /* FIXME: error data comes back in FAILURE packet */\r
8785         }\r
8786         if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {\r
8787             bombout(("Server's channel confirmation cited wrong channel"));\r
8788             crStopV;\r
8789         }\r
8790         ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);\r
8791         ssh->mainchan->halfopen = FALSE;\r
8792         ssh->mainchan->type = CHAN_MAINSESSION;\r
8793         ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
8794         ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
8795         add234(ssh->channels, ssh->mainchan);\r
8796         update_specials_menu(ssh->frontend);\r
8797         logevent("Opened channel for session");\r
8798         ssh->ncmode = FALSE;\r
8799     }\r
8801     /*\r
8802      * Now we have a channel, make dispatch table entries for\r
8803      * general channel-based messages.\r
8804      */\r
8805     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] =\r
8806     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] =\r
8807         ssh2_msg_channel_data;\r
8808     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof;\r
8809     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close;\r
8810     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
8811         ssh2_msg_channel_open_confirmation;\r
8812     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] =\r
8813         ssh2_msg_channel_open_failure;\r
8814     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] =\r
8815         ssh2_msg_channel_request;\r
8816     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] =\r
8817         ssh2_msg_channel_open;\r
8819     if (ssh->mainchan && ssh->cfg.ssh_simple) {\r
8820         /*\r
8821          * This message indicates to the server that we promise\r
8822          * not to try to run any other channel in parallel with\r
8823          * this one, so it's safe for it to advertise a very large\r
8824          * window and leave the flow control to TCP.\r
8825          */\r
8826         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
8827         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);\r
8828         ssh2_pkt_addstring(s->pktout, "simple@putty.projects.tartarus.org");\r
8829         ssh2_pkt_addbool(s->pktout, 0); /* no reply */\r
8830         ssh2_pkt_send(ssh, s->pktout);\r
8831     }\r
8833     /*\r
8834      * Potentially enable X11 forwarding.\r
8835      */\r
8836     if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward &&\r
8837         (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,\r
8838                                           ssh->cfg.x11_auth, &ssh->cfg))) {\r
8839         logevent("Requesting X11 forwarding");\r
8840         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
8841         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);\r
8842         ssh2_pkt_addstring(s->pktout, "x11-req");\r
8843         ssh2_pkt_addbool(s->pktout, 1);        /* want reply */\r
8844         ssh2_pkt_addbool(s->pktout, 0);        /* many connections */\r
8845         ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthprotoname);\r
8846         /*\r
8847          * Note that while we blank the X authentication data here, we don't\r
8848          * take any special action to blank the start of an X11 channel,\r
8849          * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection\r
8850          * without having session blanking enabled is likely to leak your\r
8851          * cookie into the log.\r
8852          */\r
8853         dont_log_password(ssh, s->pktout, PKTLOG_BLANK);\r
8854         ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring);\r
8855         end_log_omission(ssh, s->pktout);\r
8856         ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum);\r
8857         ssh2_pkt_send(ssh, s->pktout);\r
8859         crWaitUntilV(pktin);\r
8861         if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
8862             if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
8863                 bombout(("Unexpected response to X11 forwarding request:"\r
8864                          " packet type %d", pktin->type));\r
8865                 crStopV;\r
8866             }\r
8867             logevent("X11 forwarding refused");\r
8868         } else {\r
8869             logevent("X11 forwarding enabled");\r
8870             ssh->X11_fwd_enabled = TRUE;\r
8871         }\r
8872     }\r
8874     /*\r
8875      * Enable port forwardings.\r
8876      */\r
8877     ssh_setup_portfwd(ssh, &ssh->cfg);\r
8879     /*\r
8880      * Potentially enable agent forwarding.\r
8881      */\r
8882     if (ssh->mainchan && !ssh->ncmode && ssh->cfg.agentfwd && agent_exists()) {\r
8883         logevent("Requesting OpenSSH-style agent forwarding");\r
8884         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
8885         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);\r
8886         ssh2_pkt_addstring(s->pktout, "auth-agent-req@openssh.com");\r
8887         ssh2_pkt_addbool(s->pktout, 1);        /* want reply */\r
8888         ssh2_pkt_send(ssh, s->pktout);\r
8890         crWaitUntilV(pktin);\r
8892         if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
8893             if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
8894                 bombout(("Unexpected response to agent forwarding request:"\r
8895                          " packet type %d", pktin->type));\r
8896                 crStopV;\r
8897             }\r
8898             logevent("Agent forwarding refused");\r
8899         } else {\r
8900             logevent("Agent forwarding enabled");\r
8901             ssh->agentfwd_enabled = TRUE;\r
8902         }\r
8903     }\r
8905     /*\r
8906      * Now allocate a pty for the session.\r
8907      */\r
8908     if (ssh->mainchan && !ssh->ncmode && !ssh->cfg.nopty) {\r
8909         /* Unpick the terminal-speed string. */\r
8910         /* XXX perhaps we should allow no speeds to be sent. */\r
8911         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
8912         sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
8913         /* Build the pty request. */\r
8914         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
8915         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */\r
8916         ssh2_pkt_addstring(s->pktout, "pty-req");\r
8917         ssh2_pkt_addbool(s->pktout, 1);        /* want reply */\r
8918         ssh2_pkt_addstring(s->pktout, ssh->cfg.termtype);\r
8919         ssh2_pkt_adduint32(s->pktout, ssh->term_width);\r
8920         ssh2_pkt_adduint32(s->pktout, ssh->term_height);\r
8921         ssh2_pkt_adduint32(s->pktout, 0);              /* pixel width */\r
8922         ssh2_pkt_adduint32(s->pktout, 0);              /* pixel height */\r
8923         ssh2_pkt_addstring_start(s->pktout);\r
8924         parse_ttymodes(ssh, ssh->cfg.ttymodes,\r
8925                        ssh2_send_ttymode, (void *)s->pktout);\r
8926         ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_ISPEED);\r
8927         ssh2_pkt_adduint32(s->pktout, ssh->ispeed);\r
8928         ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_OSPEED);\r
8929         ssh2_pkt_adduint32(s->pktout, ssh->ospeed);\r
8930         ssh2_pkt_addstring_data(s->pktout, "\0", 1); /* TTY_OP_END */\r
8931         ssh2_pkt_send(ssh, s->pktout);\r
8932         ssh->state = SSH_STATE_INTERMED;\r
8934         crWaitUntilV(pktin);\r
8936         if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
8937             if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
8938                 bombout(("Unexpected response to pty request:"\r
8939                          " packet type %d", pktin->type));\r
8940                 crStopV;\r
8941             }\r
8942             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
8943             ssh->editing = ssh->echoing = 1;\r
8944         } else {\r
8945             logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
8946                       ssh->ospeed, ssh->ispeed);\r
8947         }\r
8948     } else {\r
8949         ssh->editing = ssh->echoing = 1;\r
8950     }\r
8952     /*\r
8953      * Send environment variables.\r
8954      * \r
8955      * Simplest thing here is to send all the requests at once, and\r
8956      * then wait for a whole bunch of successes or failures.\r
8957      */\r
8958     if (ssh->mainchan && !ssh->ncmode && *ssh->cfg.environmt) {\r
8959         char *e = ssh->cfg.environmt;\r
8960         char *var, *varend, *val;\r
8962         s->num_env = 0;\r
8964         while (*e) {\r
8965             var = e;\r
8966             while (*e && *e != '\t') e++;\r
8967             varend = e;\r
8968             if (*e == '\t') e++;\r
8969             val = e;\r
8970             while (*e) e++;\r
8971             e++;\r
8973             s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
8974             ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);\r
8975             ssh2_pkt_addstring(s->pktout, "env");\r
8976             ssh2_pkt_addbool(s->pktout, 1);            /* want reply */\r
8977             ssh2_pkt_addstring_start(s->pktout);\r
8978             ssh2_pkt_addstring_data(s->pktout, var, varend-var);\r
8979             ssh2_pkt_addstring(s->pktout, val);\r
8980             ssh2_pkt_send(ssh, s->pktout);\r
8982             s->num_env++;\r
8983         }\r
8985         logeventf(ssh, "Sent %d environment variables", s->num_env);\r
8987         s->env_ok = 0;\r
8988         s->env_left = s->num_env;\r
8990         while (s->env_left > 0) {\r
8991             crWaitUntilV(pktin);\r
8993             if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
8994                 if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
8995                     bombout(("Unexpected response to environment request:"\r
8996                              " packet type %d", pktin->type));\r
8997                     crStopV;\r
8998                 }\r
8999             } else {\r
9000                 s->env_ok++;\r
9001             }\r
9003             s->env_left--;\r
9004         }\r
9006         if (s->env_ok == s->num_env) {\r
9007             logevent("All environment variables successfully set");\r
9008         } else if (s->env_ok == 0) {\r
9009             logevent("All environment variables refused");\r
9010             c_write_str(ssh, "Server refused to set environment variables\r\n");\r
9011         } else {\r
9012             logeventf(ssh, "%d environment variables refused",\r
9013                       s->num_env - s->env_ok);\r
9014             c_write_str(ssh, "Server refused to set all environment variables\r\n");\r
9015         }\r
9016     }\r
9018     /*\r
9019      * Start a shell or a remote command. We may have to attempt\r
9020      * this twice if the config data has provided a second choice\r
9021      * of command.\r
9022      */\r
9023     if (ssh->mainchan && !ssh->ncmode) while (1) {\r
9024         int subsys;\r
9025         char *cmd;\r
9027         if (ssh->fallback_cmd) {\r
9028             subsys = ssh->cfg.ssh_subsys2;\r
9029             cmd = ssh->cfg.remote_cmd_ptr2;\r
9030         } else {\r
9031             subsys = ssh->cfg.ssh_subsys;\r
9032             cmd = ssh->cfg.remote_cmd_ptr;\r
9033             if (!cmd) cmd = ssh->cfg.remote_cmd;\r
9034         }\r
9036         s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
9037         ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */\r
9038         if (subsys) {\r
9039             ssh2_pkt_addstring(s->pktout, "subsystem");\r
9040             ssh2_pkt_addbool(s->pktout, 1);            /* want reply */\r
9041             ssh2_pkt_addstring(s->pktout, cmd);\r
9042         } else if (*cmd) {\r
9043             ssh2_pkt_addstring(s->pktout, "exec");\r
9044             ssh2_pkt_addbool(s->pktout, 1);            /* want reply */\r
9045             ssh2_pkt_addstring(s->pktout, cmd);\r
9046         } else {\r
9047             ssh2_pkt_addstring(s->pktout, "shell");\r
9048             ssh2_pkt_addbool(s->pktout, 1);            /* want reply */\r
9049         }\r
9050         ssh2_pkt_send(ssh, s->pktout);\r
9052         crWaitUntilV(pktin);\r
9054         if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
9055             if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
9056                 bombout(("Unexpected response to shell/command request:"\r
9057                          " packet type %d", pktin->type));\r
9058                 crStopV;\r
9059             }\r
9060             /*\r
9061              * We failed to start the command. If this is the\r
9062              * fallback command, we really are finished; if it's\r
9063              * not, and if the fallback command exists, try falling\r
9064              * back to it before complaining.\r
9065              */\r
9066             if (!ssh->fallback_cmd && ssh->cfg.remote_cmd_ptr2 != NULL) {\r
9067                 logevent("Primary command failed; attempting fallback");\r
9068                 ssh->fallback_cmd = TRUE;\r
9069                 continue;\r
9070             }\r
9071             bombout(("Server refused to start a shell/command"));\r
9072             crStopV;\r
9073         } else {\r
9074             logevent("Started a shell/command");\r
9075         }\r
9076         break;\r
9077     }\r
9079     ssh->state = SSH_STATE_SESSION;\r
9080     if (ssh->size_needed)\r
9081         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
9082     if (ssh->eof_needed)\r
9083         ssh_special(ssh, TS_EOF);\r
9085     /*\r
9086      * All the initial channel requests are done, so install the default\r
9087      * failure handler.\r
9088      */\r
9089     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_success;\r
9090     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_failure;\r
9092     /*\r
9093      * Transfer data!\r
9094      */\r
9095     if (ssh->ldisc)\r
9096         ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */\r
9097     if (ssh->mainchan)\r
9098         ssh->send_ok = 1;\r
9099     while (1) {\r
9100         crReturnV;\r
9101         s->try_send = FALSE;\r
9102         if (pktin) {\r
9104             /*\r
9105              * _All_ the connection-layer packets we expect to\r
9106              * receive are now handled by the dispatch table.\r
9107              * Anything that reaches here must be bogus.\r
9108              */\r
9110             bombout(("Strange packet received: type %d", pktin->type));\r
9111             crStopV;\r
9112         } else if (ssh->mainchan) {\r
9113             /*\r
9114              * We have spare data. Add it to the channel buffer.\r
9115              */\r
9116             ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen);\r
9117             s->try_send = TRUE;\r
9118         }\r
9119         if (s->try_send) {\r
9120             int i;\r
9121             struct ssh_channel *c;\r
9122             /*\r
9123              * Try to send data on all channels if we can.\r
9124              */\r
9125             for (i = 0; NULL != (c = index234(ssh->channels, i)); i++)\r
9126                 ssh2_try_send_and_unthrottle(ssh, c);\r
9127         }\r
9128     }\r
9130     crFinishV;\r
9133 /*\r
9134  * Handlers for SSH-2 messages that might arrive at any moment.\r
9135  */\r
9136 static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
9138     /* log reason code in disconnect message */\r
9139     char *buf, *msg;\r
9140     int reason, msglen;\r
9142     reason = ssh_pkt_getuint32(pktin);\r
9143     ssh_pkt_getstring(pktin, &msg, &msglen);\r
9145     if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {\r
9146         buf = dupprintf("Received disconnect message (%s)",\r
9147                         ssh2_disconnect_reasons[reason]);\r
9148     } else {\r
9149         buf = dupprintf("Received disconnect message (unknown"\r
9150                         " type %d)", reason);\r
9151     }\r
9152     logevent(buf);\r
9153     sfree(buf);\r
9154     buf = dupprintf("Disconnection message text: %.*s",\r
9155                     msglen, msg);\r
9156     logevent(buf);\r
9157     bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"",\r
9158              reason,\r
9159              (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?\r
9160              ssh2_disconnect_reasons[reason] : "unknown",\r
9161              msglen, msg));\r
9162     sfree(buf);\r
9165 static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)\r
9167     /* log the debug message */\r
9168     char *msg;\r
9169     int msglen;\r
9171     /* XXX maybe we should actually take notice of the return value */\r
9172     ssh2_pkt_getbool(pktin);\r
9173     ssh_pkt_getstring(pktin, &msg, &msglen);\r
9175     logeventf(ssh, "Remote debug message: %.*s", msglen, msg);\r
9178 static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)\r
9180     struct Packet *pktout;\r
9181     pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);\r
9182     ssh2_pkt_adduint32(pktout, pktin->sequence);\r
9183     /*\r
9184      * UNIMPLEMENTED messages MUST appear in the same order as the\r
9185      * messages they respond to. Hence, never queue them.\r
9186      */\r
9187     ssh2_pkt_send_noqueue(ssh, pktout);\r
9190 /*\r
9191  * Handle the top-level SSH-2 protocol.\r
9192  */\r
9193 static void ssh2_protocol_setup(Ssh ssh)\r
9195     int i;\r
9197     /*\r
9198      * Most messages cause SSH2_MSG_UNIMPLEMENTED.\r
9199      */\r
9200     for (i = 0; i < 256; i++)\r
9201         ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;\r
9203     /*\r
9204      * Any message we actually understand, we set to NULL so that\r
9205      * the coroutines will get it.\r
9206      */\r
9207     ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = NULL;\r
9208     ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = NULL;\r
9209     ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = NULL;\r
9210     ssh->packet_dispatch[SSH2_MSG_KEXINIT] = NULL;\r
9211     ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = NULL;\r
9212     ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = NULL;\r
9213     ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = NULL;\r
9214     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = NULL; duplicate case value */\r
9215     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = NULL; duplicate case value */\r
9216     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = NULL;\r
9217     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = NULL;\r
9218     ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = NULL;\r
9219     ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = NULL;\r
9220     ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = NULL;\r
9221     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;\r
9222     ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = NULL;\r
9223     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = NULL; duplicate case value */\r
9224     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = NULL; duplicate case value */\r
9225     ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = NULL;\r
9226     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = NULL;\r
9227     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = NULL;\r
9228     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = NULL;\r
9229     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = NULL;\r
9230     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = NULL;\r
9231     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = NULL;\r
9232     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = NULL;\r
9233     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = NULL;\r
9234     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = NULL;\r
9235     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = NULL;\r
9236     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = NULL;\r
9237     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = NULL;\r
9238     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = NULL;\r
9239     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = NULL;\r
9241     /*\r
9242      * These special message types we install handlers for.\r
9243      */\r
9244     ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;\r
9245     ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with SSH-1 */\r
9246     ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;\r
9249 static void ssh2_timer(void *ctx, long now)\r
9251     Ssh ssh = (Ssh)ctx;\r
9253     if (ssh->state == SSH_STATE_CLOSED)\r
9254         return;\r
9256     if (!ssh->kex_in_progress && ssh->cfg.ssh_rekey_time != 0 &&\r
9257         now - ssh->next_rekey >= 0) {\r
9258         do_ssh2_transport(ssh, "timeout", -1, NULL);\r
9259     }\r
9262 static void ssh2_protocol(Ssh ssh, void *vin, int inlen,\r
9263                           struct Packet *pktin)\r
9265     unsigned char *in = (unsigned char *)vin;\r
9266     if (ssh->state == SSH_STATE_CLOSED)\r
9267         return;\r
9269     if (pktin) {\r
9270         ssh->incoming_data_size += pktin->encrypted_len;\r
9271         if (!ssh->kex_in_progress &&\r
9272             ssh->max_data_size != 0 &&\r
9273             ssh->incoming_data_size > ssh->max_data_size)\r
9274             do_ssh2_transport(ssh, "too much data received", -1, NULL);\r
9275     }\r
9277     if (pktin && ssh->packet_dispatch[pktin->type]) {\r
9278         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
9279         return;\r
9280     }\r
9282     if (!ssh->protocol_initial_phase_done ||\r
9283         (pktin && pktin->type >= 20 && pktin->type < 50)) {\r
9284         if (do_ssh2_transport(ssh, in, inlen, pktin) &&\r
9285             !ssh->protocol_initial_phase_done) {\r
9286             ssh->protocol_initial_phase_done = TRUE;\r
9287             /*\r
9288              * Allow authconn to initialise itself.\r
9289              */\r
9290             do_ssh2_authconn(ssh, NULL, 0, NULL);\r
9291         }\r
9292     } else {\r
9293         do_ssh2_authconn(ssh, in, inlen, pktin);\r
9294     }\r
9297 /*\r
9298  * Called to set up the connection.\r
9299  *\r
9300  * Returns an error message, or NULL on success.\r
9301  */\r
9302 static const char *ssh_init(void *frontend_handle, void **backend_handle,\r
9303                             Config *cfg,\r
9304                             char *host, int port, char **realhost, int nodelay,\r
9305                             int keepalive)\r
9307     const char *p;\r
9308     Ssh ssh;\r
9310     ssh = snew(struct ssh_tag);\r
9311     ssh->cfg = *cfg;                   /* STRUCTURE COPY */\r
9312     ssh->version = 0;                  /* when not ready yet */\r
9313     ssh->s = NULL;\r
9314     ssh->cipher = NULL;\r
9315     ssh->v1_cipher_ctx = NULL;\r
9316     ssh->crcda_ctx = NULL;\r
9317     ssh->cscipher = NULL;\r
9318     ssh->cs_cipher_ctx = NULL;\r
9319     ssh->sccipher = NULL;\r
9320     ssh->sc_cipher_ctx = NULL;\r
9321     ssh->csmac = NULL;\r
9322     ssh->cs_mac_ctx = NULL;\r
9323     ssh->scmac = NULL;\r
9324     ssh->sc_mac_ctx = NULL;\r
9325     ssh->cscomp = NULL;\r
9326     ssh->cs_comp_ctx = NULL;\r
9327     ssh->sccomp = NULL;\r
9328     ssh->sc_comp_ctx = NULL;\r
9329     ssh->kex = NULL;\r
9330     ssh->kex_ctx = NULL;\r
9331     ssh->hostkey = NULL;\r
9332     ssh->exitcode = -1;\r
9333     ssh->close_expected = FALSE;\r
9334     ssh->clean_exit = FALSE;\r
9335     ssh->state = SSH_STATE_PREPACKET;\r
9336     ssh->size_needed = FALSE;\r
9337     ssh->eof_needed = FALSE;\r
9338     ssh->ldisc = NULL;\r
9339     ssh->logctx = NULL;\r
9340     ssh->deferred_send_data = NULL;\r
9341     ssh->deferred_len = 0;\r
9342     ssh->deferred_size = 0;\r
9343     ssh->fallback_cmd = 0;\r
9344     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
9345     ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
9346     ssh->x11disp = NULL;\r
9347     ssh->v1_compressing = FALSE;\r
9348     ssh->v2_outgoing_sequence = 0;\r
9349     ssh->ssh1_rdpkt_crstate = 0;\r
9350     ssh->ssh2_rdpkt_crstate = 0;\r
9351     ssh->do_ssh_init_crstate = 0;\r
9352     ssh->ssh_gotdata_crstate = 0;\r
9353     ssh->do_ssh1_connection_crstate = 0;\r
9354     ssh->do_ssh1_login_crstate = 0;\r
9355     ssh->do_ssh2_transport_crstate = 0;\r
9356     ssh->do_ssh2_authconn_crstate = 0;\r
9357     ssh->do_ssh_init_state = NULL;\r
9358     ssh->do_ssh1_login_state = NULL;\r
9359     ssh->do_ssh2_transport_state = NULL;\r
9360     ssh->do_ssh2_authconn_state = NULL;\r
9361     ssh->v_c = NULL;\r
9362     ssh->v_s = NULL;\r
9363     ssh->mainchan = NULL;\r
9364     ssh->throttled_all = 0;\r
9365     ssh->v1_stdout_throttling = 0;\r
9366     ssh->queue = NULL;\r
9367     ssh->queuelen = ssh->queuesize = 0;\r
9368     ssh->queueing = FALSE;\r
9369     ssh->qhead = ssh->qtail = NULL;\r
9370     ssh->deferred_rekey_reason = NULL;\r
9371     bufchain_init(&ssh->queued_incoming_data);\r
9372     ssh->frozen = FALSE;\r
9374     *backend_handle = ssh;\r
9376 #ifdef MSCRYPTOAPI\r
9377     if (crypto_startup() == 0)\r
9378         return "Microsoft high encryption pack not installed!";\r
9379 #endif\r
9381     ssh->frontend = frontend_handle;\r
9382     ssh->term_width = ssh->cfg.width;\r
9383     ssh->term_height = ssh->cfg.height;\r
9385     ssh->channels = NULL;\r
9386     ssh->rportfwds = NULL;\r
9387     ssh->portfwds = NULL;\r
9389     ssh->send_ok = 0;\r
9390     ssh->editing = 0;\r
9391     ssh->echoing = 0;\r
9392     ssh->conn_throttle_count = 0;\r
9393     ssh->overall_bufsize = 0;\r
9394     ssh->fallback_cmd = 0;\r
9396     ssh->protocol = NULL;\r
9398     ssh->protocol_initial_phase_done = FALSE;\r
9400     ssh->pinger = NULL;\r
9402     ssh->incoming_data_size = ssh->outgoing_data_size =\r
9403         ssh->deferred_data_size = 0L;\r
9404     ssh->max_data_size = parse_blocksize(ssh->cfg.ssh_rekey_data);\r
9405     ssh->kex_in_progress = FALSE;\r
9407 #ifndef NO_GSSAPI\r
9408     ssh->gsslibs = NULL;\r
9409 #endif\r
9411     p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);\r
9412     if (p != NULL)\r
9413         return p;\r
9415     random_ref();\r
9417     return NULL;\r
9420 static void ssh_free(void *handle)\r
9422     Ssh ssh = (Ssh) handle;\r
9423     struct ssh_channel *c;\r
9424     struct ssh_rportfwd *pf;\r
9426     if (ssh->v1_cipher_ctx)\r
9427         ssh->cipher->free_context(ssh->v1_cipher_ctx);\r
9428     if (ssh->cs_cipher_ctx)\r
9429         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
9430     if (ssh->sc_cipher_ctx)\r
9431         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
9432     if (ssh->cs_mac_ctx)\r
9433         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
9434     if (ssh->sc_mac_ctx)\r
9435         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
9436     if (ssh->cs_comp_ctx) {\r
9437         if (ssh->cscomp)\r
9438             ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
9439         else\r
9440             zlib_compress_cleanup(ssh->cs_comp_ctx);\r
9441     }\r
9442     if (ssh->sc_comp_ctx) {\r
9443         if (ssh->sccomp)\r
9444             ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
9445         else\r
9446             zlib_decompress_cleanup(ssh->sc_comp_ctx);\r
9447     }\r
9448     if (ssh->kex_ctx)\r
9449         dh_cleanup(ssh->kex_ctx);\r
9450     sfree(ssh->savedhost);\r
9452     while (ssh->queuelen-- > 0)\r
9453         ssh_free_packet(ssh->queue[ssh->queuelen]);\r
9454     sfree(ssh->queue);\r
9456     while (ssh->qhead) {\r
9457         struct queued_handler *qh = ssh->qhead;\r
9458         ssh->qhead = qh->next;\r
9459         sfree(ssh->qhead);\r
9460     }\r
9461     ssh->qhead = ssh->qtail = NULL;\r
9463     if (ssh->channels) {\r
9464         while ((c = delpos234(ssh->channels, 0)) != NULL) {\r
9465             switch (c->type) {\r
9466               case CHAN_X11:\r
9467                 if (c->u.x11.s != NULL)\r
9468                     x11_close(c->u.x11.s);\r
9469                 break;\r
9470               case CHAN_SOCKDATA:\r
9471               case CHAN_SOCKDATA_DORMANT:\r
9472                 if (c->u.pfd.s != NULL)\r
9473                     pfd_close(c->u.pfd.s);\r
9474                 break;\r
9475             }\r
9476             sfree(c);\r
9477         }\r
9478         freetree234(ssh->channels);\r
9479         ssh->channels = NULL;\r
9480     }\r
9482     if (ssh->rportfwds) {\r
9483         while ((pf = delpos234(ssh->rportfwds, 0)) != NULL)\r
9484             free_rportfwd(pf);\r
9485         freetree234(ssh->rportfwds);\r
9486         ssh->rportfwds = NULL;\r
9487     }\r
9488     sfree(ssh->deferred_send_data);\r
9489     if (ssh->x11disp)\r
9490         x11_free_display(ssh->x11disp);\r
9491     sfree(ssh->do_ssh_init_state);\r
9492     sfree(ssh->do_ssh1_login_state);\r
9493     sfree(ssh->do_ssh2_transport_state);\r
9494     sfree(ssh->do_ssh2_authconn_state);\r
9495     sfree(ssh->v_c);\r
9496     sfree(ssh->v_s);\r
9497     sfree(ssh->fullhostname);\r
9498     if (ssh->crcda_ctx) {\r
9499         crcda_free_context(ssh->crcda_ctx);\r
9500         ssh->crcda_ctx = NULL;\r
9501     }\r
9502     if (ssh->s)\r
9503         ssh_do_close(ssh, TRUE);\r
9504     expire_timer_context(ssh);\r
9505     if (ssh->pinger)\r
9506         pinger_free(ssh->pinger);\r
9507     bufchain_clear(&ssh->queued_incoming_data);\r
9508 #ifndef NO_GSSAPI\r
9509     if (ssh->gsslibs)\r
9510         ssh_gss_cleanup(ssh->gsslibs);\r
9511 #endif\r
9512     sfree(ssh);\r
9514     random_unref();\r
9517 /*\r
9518  * Reconfigure the SSH backend.\r
9519  */\r
9520 static void ssh_reconfig(void *handle, Config *cfg)\r
9522     Ssh ssh = (Ssh) handle;\r
9523     char *rekeying = NULL, rekey_mandatory = FALSE;\r
9524     unsigned long old_max_data_size;\r
9526     pinger_reconfig(ssh->pinger, &ssh->cfg, cfg);\r
9527     if (ssh->portfwds)\r
9528         ssh_setup_portfwd(ssh, cfg);\r
9530     if (ssh->cfg.ssh_rekey_time != cfg->ssh_rekey_time &&\r
9531         cfg->ssh_rekey_time != 0) {\r
9532         long new_next = ssh->last_rekey + cfg->ssh_rekey_time*60*TICKSPERSEC;\r
9533         long now = GETTICKCOUNT();\r
9535         if (new_next - now < 0) {\r
9536             rekeying = "timeout shortened";\r
9537         } else {\r
9538             ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh);\r
9539         }\r
9540     }\r
9542     old_max_data_size = ssh->max_data_size;\r
9543     ssh->max_data_size = parse_blocksize(cfg->ssh_rekey_data);\r
9544     if (old_max_data_size != ssh->max_data_size &&\r
9545         ssh->max_data_size != 0) {\r
9546         if (ssh->outgoing_data_size > ssh->max_data_size ||\r
9547             ssh->incoming_data_size > ssh->max_data_size)\r
9548             rekeying = "data limit lowered";\r
9549     }\r
9551     if (ssh->cfg.compression != cfg->compression) {\r
9552         rekeying = "compression setting changed";\r
9553         rekey_mandatory = TRUE;\r
9554     }\r
9556     if (ssh->cfg.ssh2_des_cbc != cfg->ssh2_des_cbc ||\r
9557         memcmp(ssh->cfg.ssh_cipherlist, cfg->ssh_cipherlist,\r
9558                sizeof(ssh->cfg.ssh_cipherlist))) {\r
9559         rekeying = "cipher settings changed";\r
9560         rekey_mandatory = TRUE;\r
9561     }\r
9563     ssh->cfg = *cfg;                   /* STRUCTURE COPY */\r
9565     if (rekeying) {\r
9566         if (!ssh->kex_in_progress) {\r
9567             do_ssh2_transport(ssh, rekeying, -1, NULL);\r
9568         } else if (rekey_mandatory) {\r
9569             ssh->deferred_rekey_reason = rekeying;\r
9570         }\r
9571     }\r
9574 /*\r
9575  * Called to send data down the SSH connection.\r
9576  */\r
9577 static int ssh_send(void *handle, char *buf, int len)\r
9579     Ssh ssh = (Ssh) handle;\r
9581     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
9582         return 0;\r
9584     ssh->protocol(ssh, (unsigned char *)buf, len, 0);\r
9586     return ssh_sendbuffer(ssh);\r
9589 /*\r
9590  * Called to query the current amount of buffered stdin data.\r
9591  */\r
9592 static int ssh_sendbuffer(void *handle)\r
9594     Ssh ssh = (Ssh) handle;\r
9595     int override_value;\r
9597     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
9598         return 0;\r
9600     /*\r
9601      * If the SSH socket itself has backed up, add the total backup\r
9602      * size on that to any individual buffer on the stdin channel.\r
9603      */\r
9604     override_value = 0;\r
9605     if (ssh->throttled_all)\r
9606         override_value = ssh->overall_bufsize;\r
9608     if (ssh->version == 1) {\r
9609         return override_value;\r
9610     } else if (ssh->version == 2) {\r
9611         if (!ssh->mainchan || ssh->mainchan->closes > 0)\r
9612             return override_value;\r
9613         else\r
9614             return (override_value +\r
9615                     bufchain_size(&ssh->mainchan->v.v2.outbuffer));\r
9616     }\r
9618     return 0;\r
9621 /*\r
9622  * Called to set the size of the window from SSH's POV.\r
9623  */\r
9624 static void ssh_size(void *handle, int width, int height)\r
9626     Ssh ssh = (Ssh) handle;\r
9627     struct Packet *pktout;\r
9629     ssh->term_width = width;\r
9630     ssh->term_height = height;\r
9632     switch (ssh->state) {\r
9633       case SSH_STATE_BEFORE_SIZE:\r
9634       case SSH_STATE_PREPACKET:\r
9635       case SSH_STATE_CLOSED:\r
9636         break;                         /* do nothing */\r
9637       case SSH_STATE_INTERMED:\r
9638         ssh->size_needed = TRUE;       /* buffer for later */\r
9639         break;\r
9640       case SSH_STATE_SESSION:\r
9641         if (!ssh->cfg.nopty) {\r
9642             if (ssh->version == 1) {\r
9643                 send_packet(ssh, SSH1_CMSG_WINDOW_SIZE,\r
9644                             PKT_INT, ssh->term_height,\r
9645                             PKT_INT, ssh->term_width,\r
9646                             PKT_INT, 0, PKT_INT, 0, PKT_END);\r
9647             } else if (ssh->mainchan) {\r
9648                 pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
9649                 ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);\r
9650                 ssh2_pkt_addstring(pktout, "window-change");\r
9651                 ssh2_pkt_addbool(pktout, 0);\r
9652                 ssh2_pkt_adduint32(pktout, ssh->term_width);\r
9653                 ssh2_pkt_adduint32(pktout, ssh->term_height);\r
9654                 ssh2_pkt_adduint32(pktout, 0);\r
9655                 ssh2_pkt_adduint32(pktout, 0);\r
9656                 ssh2_pkt_send(ssh, pktout);\r
9657             }\r
9658         }\r
9659         break;\r
9660     }\r
9663 /*\r
9664  * Return a list of the special codes that make sense in this\r
9665  * protocol.\r
9666  */\r
9667 static const struct telnet_special *ssh_get_specials(void *handle)\r
9669     static const struct telnet_special ssh1_ignore_special[] = {\r
9670         {"IGNORE message", TS_NOP}\r
9671     };\r
9672     static const struct telnet_special ssh2_ignore_special[] = {\r
9673         {"IGNORE message", TS_NOP},\r
9674     };\r
9675     static const struct telnet_special ssh2_rekey_special[] = {\r
9676         {"Repeat key exchange", TS_REKEY},\r
9677     };\r
9678     static const struct telnet_special ssh2_session_specials[] = {\r
9679         {NULL, TS_SEP},\r
9680         {"Break", TS_BRK},\r
9681         /* These are the signal names defined by RFC 4254.\r
9682          * They include all the ISO C signals, but are a subset of the POSIX\r
9683          * required signals. */\r
9684         {"SIGINT (Interrupt)", TS_SIGINT},\r
9685         {"SIGTERM (Terminate)", TS_SIGTERM},\r
9686         {"SIGKILL (Kill)", TS_SIGKILL},\r
9687         {"SIGQUIT (Quit)", TS_SIGQUIT},\r
9688         {"SIGHUP (Hangup)", TS_SIGHUP},\r
9689         {"More signals", TS_SUBMENU},\r
9690           {"SIGABRT", TS_SIGABRT}, {"SIGALRM", TS_SIGALRM},\r
9691           {"SIGFPE",  TS_SIGFPE},  {"SIGILL",  TS_SIGILL},\r
9692           {"SIGPIPE", TS_SIGPIPE}, {"SIGSEGV", TS_SIGSEGV},\r
9693           {"SIGUSR1", TS_SIGUSR1}, {"SIGUSR2", TS_SIGUSR2},\r
9694         {NULL, TS_EXITMENU}\r
9695     };\r
9696     static const struct telnet_special specials_end[] = {\r
9697         {NULL, TS_EXITMENU}\r
9698     };\r
9699     /* XXX review this length for any changes: */\r
9700     static struct telnet_special ssh_specials[lenof(ssh2_ignore_special) +\r
9701                                               lenof(ssh2_rekey_special) +\r
9702                                               lenof(ssh2_session_specials) +\r
9703                                               lenof(specials_end)];\r
9704     Ssh ssh = (Ssh) handle;\r
9705     int i = 0;\r
9706 #define ADD_SPECIALS(name) \\r
9707     do { \\r
9708         assert((i + lenof(name)) <= lenof(ssh_specials)); \\r
9709         memcpy(&ssh_specials[i], name, sizeof name); \\r
9710         i += lenof(name); \\r
9711     } while(0)\r
9713     if (ssh->version == 1) {\r
9714         /* Don't bother offering IGNORE if we've decided the remote\r
9715          * won't cope with it, since we wouldn't bother sending it if\r
9716          * asked anyway. */\r
9717         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
9718             ADD_SPECIALS(ssh1_ignore_special);\r
9719     } else if (ssh->version == 2) {\r
9720         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE))\r
9721             ADD_SPECIALS(ssh2_ignore_special);\r
9722         if (!(ssh->remote_bugs & BUG_SSH2_REKEY))\r
9723             ADD_SPECIALS(ssh2_rekey_special);\r
9724         if (ssh->mainchan)\r
9725             ADD_SPECIALS(ssh2_session_specials);\r
9726     } /* else we're not ready yet */\r
9728     if (i) {\r
9729         ADD_SPECIALS(specials_end);\r
9730         return ssh_specials;\r
9731     } else {\r
9732         return NULL;\r
9733     }\r
9734 #undef ADD_SPECIALS\r
9737 /*\r
9738  * Send special codes. TS_EOF is useful for `plink', so you\r
9739  * can send an EOF and collect resulting output (e.g. `plink\r
9740  * hostname sort').\r
9741  */\r
9742 static void ssh_special(void *handle, Telnet_Special code)\r
9744     Ssh ssh = (Ssh) handle;\r
9745     struct Packet *pktout;\r
9747     if (code == TS_EOF) {\r
9748         if (ssh->state != SSH_STATE_SESSION) {\r
9749             /*\r
9750              * Buffer the EOF in case we are pre-SESSION, so we can\r
9751              * send it as soon as we reach SESSION.\r
9752              */\r
9753             if (code == TS_EOF)\r
9754                 ssh->eof_needed = TRUE;\r
9755             return;\r
9756         }\r
9757         if (ssh->version == 1) {\r
9758             send_packet(ssh, SSH1_CMSG_EOF, PKT_END);\r
9759         } else if (ssh->mainchan) {\r
9760             struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);\r
9761             ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);\r
9762             ssh2_pkt_send(ssh, pktout);\r
9763             ssh->send_ok = 0;          /* now stop trying to read from stdin */\r
9764         }\r
9765         logevent("Sent EOF message");\r
9766     } else if (code == TS_PING || code == TS_NOP) {\r
9767         if (ssh->state == SSH_STATE_CLOSED\r
9768             || ssh->state == SSH_STATE_PREPACKET) return;\r
9769         if (ssh->version == 1) {\r
9770             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
9771                 send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);\r
9772         } else {\r
9773             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
9774                 pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
9775                 ssh2_pkt_addstring_start(pktout);\r
9776                 ssh2_pkt_send_noqueue(ssh, pktout);\r
9777             }\r
9778         }\r
9779     } else if (code == TS_REKEY) {\r
9780         if (!ssh->kex_in_progress && ssh->version == 2) {\r
9781             do_ssh2_transport(ssh, "at user request", -1, NULL);\r
9782         }\r
9783     } else if (code == TS_BRK) {\r
9784         if (ssh->state == SSH_STATE_CLOSED\r
9785             || ssh->state == SSH_STATE_PREPACKET) return;\r
9786         if (ssh->version == 1) {\r
9787             logevent("Unable to send BREAK signal in SSH-1");\r
9788         } else if (ssh->mainchan) {\r
9789             pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
9790             ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);\r
9791             ssh2_pkt_addstring(pktout, "break");\r
9792             ssh2_pkt_addbool(pktout, 0);\r
9793             ssh2_pkt_adduint32(pktout, 0);   /* default break length */\r
9794             ssh2_pkt_send(ssh, pktout);\r
9795         }\r
9796     } else {\r
9797         /* Is is a POSIX signal? */\r
9798         char *signame = NULL;\r
9799         if (code == TS_SIGABRT) signame = "ABRT";\r
9800         if (code == TS_SIGALRM) signame = "ALRM";\r
9801         if (code == TS_SIGFPE)  signame = "FPE";\r
9802         if (code == TS_SIGHUP)  signame = "HUP";\r
9803         if (code == TS_SIGILL)  signame = "ILL";\r
9804         if (code == TS_SIGINT)  signame = "INT";\r
9805         if (code == TS_SIGKILL) signame = "KILL";\r
9806         if (code == TS_SIGPIPE) signame = "PIPE";\r
9807         if (code == TS_SIGQUIT) signame = "QUIT";\r
9808         if (code == TS_SIGSEGV) signame = "SEGV";\r
9809         if (code == TS_SIGTERM) signame = "TERM";\r
9810         if (code == TS_SIGUSR1) signame = "USR1";\r
9811         if (code == TS_SIGUSR2) signame = "USR2";\r
9812         /* The SSH-2 protocol does in principle support arbitrary named\r
9813          * signals, including signame@domain, but we don't support those. */\r
9814         if (signame) {\r
9815             /* It's a signal. */\r
9816             if (ssh->version == 2 && ssh->mainchan) {\r
9817                 pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
9818                 ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);\r
9819                 ssh2_pkt_addstring(pktout, "signal");\r
9820                 ssh2_pkt_addbool(pktout, 0);\r
9821                 ssh2_pkt_addstring(pktout, signame);\r
9822                 ssh2_pkt_send(ssh, pktout);\r
9823                 logeventf(ssh, "Sent signal SIG%s", signame);\r
9824             }\r
9825         } else {\r
9826             /* Never heard of it. Do nothing */\r
9827         }\r
9828     }\r
9831 void *new_sock_channel(void *handle, Socket s)\r
9833     Ssh ssh = (Ssh) handle;\r
9834     struct ssh_channel *c;\r
9835     c = snew(struct ssh_channel);\r
9837     c->ssh = ssh;\r
9838     ssh2_channel_init(c);\r
9839     c->halfopen = TRUE;\r
9840     c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */\r
9841     c->u.pfd.s = s;\r
9842     add234(ssh->channels, c);\r
9843     return c;\r
9846 /*\r
9847  * This is called when stdout/stderr (the entity to which\r
9848  * from_backend sends data) manages to clear some backlog.\r
9849  */\r
9850 static void ssh_unthrottle(void *handle, int bufsize)\r
9852     Ssh ssh = (Ssh) handle;\r
9853     int buflimit;\r
9855     if (ssh->version == 1) {\r
9856         if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {\r
9857             ssh->v1_stdout_throttling = 0;\r
9858             ssh_throttle_conn(ssh, -1);\r
9859         }\r
9860     } else {\r
9861         if (ssh->mainchan) {\r
9862             ssh2_set_window(ssh->mainchan,\r
9863                             bufsize < ssh->mainchan->v.v2.locmaxwin ?\r
9864                             ssh->mainchan->v.v2.locmaxwin - bufsize : 0);\r
9865             if (ssh->cfg.ssh_simple)\r
9866                 buflimit = 0;\r
9867             else\r
9868                 buflimit = ssh->mainchan->v.v2.locmaxwin;\r
9869             if (ssh->mainchan->throttling_conn && bufsize <= buflimit) {\r
9870                 ssh->mainchan->throttling_conn = 0;\r
9871                 ssh_throttle_conn(ssh, -1);\r
9872             }\r
9873         }\r
9874     }\r
9877 void ssh_send_port_open(void *channel, char *hostname, int port, char *org)\r
9879     struct ssh_channel *c = (struct ssh_channel *)channel;\r
9880     Ssh ssh = c->ssh;\r
9881     struct Packet *pktout;\r
9883     logeventf(ssh, "Opening forwarded connection to %s:%d", hostname, port);\r
9885     if (ssh->version == 1) {\r
9886         send_packet(ssh, SSH1_MSG_PORT_OPEN,\r
9887                     PKT_INT, c->localid,\r
9888                     PKT_STR, hostname,\r
9889                     PKT_INT, port,\r
9890                     /* PKT_STR, <org:orgport>, */\r
9891                     PKT_END);\r
9892     } else {\r
9893         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);\r
9894         ssh2_pkt_addstring(pktout, "direct-tcpip");\r
9895         ssh2_pkt_adduint32(pktout, c->localid);\r
9896         ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */\r
9897         ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
9898         ssh2_pkt_addstring(pktout, hostname);\r
9899         ssh2_pkt_adduint32(pktout, port);\r
9900         /*\r
9901          * We make up values for the originator data; partly it's\r
9902          * too much hassle to keep track, and partly I'm not\r
9903          * convinced the server should be told details like that\r
9904          * about my local network configuration.\r
9905          * The "originator IP address" is syntactically a numeric\r
9906          * IP address, and some servers (e.g., Tectia) get upset\r
9907          * if it doesn't match this syntax.\r
9908          */\r
9909         ssh2_pkt_addstring(pktout, "0.0.0.0");\r
9910         ssh2_pkt_adduint32(pktout, 0);\r
9911         ssh2_pkt_send(ssh, pktout);\r
9912     }\r
9915 static int ssh_connected(void *handle)\r
9917     Ssh ssh = (Ssh) handle;\r
9918     return ssh->s != NULL;\r
9921 static int ssh_sendok(void *handle)\r
9923     Ssh ssh = (Ssh) handle;\r
9924     return ssh->send_ok;\r
9927 static int ssh_ldisc(void *handle, int option)\r
9929     Ssh ssh = (Ssh) handle;\r
9930     if (option == LD_ECHO)\r
9931         return ssh->echoing;\r
9932     if (option == LD_EDIT)\r
9933         return ssh->editing;\r
9934     return FALSE;\r
9937 static void ssh_provide_ldisc(void *handle, void *ldisc)\r
9939     Ssh ssh = (Ssh) handle;\r
9940     ssh->ldisc = ldisc;\r
9943 static void ssh_provide_logctx(void *handle, void *logctx)\r
9945     Ssh ssh = (Ssh) handle;\r
9946     ssh->logctx = logctx;\r
9949 static int ssh_return_exitcode(void *handle)\r
9951     Ssh ssh = (Ssh) handle;\r
9952     if (ssh->s != NULL)\r
9953         return -1;\r
9954     else\r
9955         return (ssh->exitcode >= 0 ? ssh->exitcode : INT_MAX);\r
9958 /*\r
9959  * cfg_info for SSH is the currently running version of the\r
9960  * protocol. (1 for 1; 2 for 2; 0 for not-decided-yet.)\r
9961  */\r
9962 static int ssh_cfg_info(void *handle)\r
9964     Ssh ssh = (Ssh) handle;\r
9965     return ssh->version;\r
9968 /*\r
9969  * Gross hack: pscp will try to start SFTP but fall back to scp1 if\r
9970  * that fails. This variable is the means by which scp.c can reach\r
9971  * into the SSH code and find out which one it got.\r
9972  */\r
9973 extern int ssh_fallback_cmd(void *handle)\r
9975     Ssh ssh = (Ssh) handle;\r
9976     return ssh->fallback_cmd;\r
9979 Backend ssh_backend = {\r
9980     ssh_init,\r
9981     ssh_free,\r
9982     ssh_reconfig,\r
9983     ssh_send,\r
9984     ssh_sendbuffer,\r
9985     ssh_size,\r
9986     ssh_special,\r
9987     ssh_get_specials,\r
9988     ssh_connected,\r
9989     ssh_return_exitcode,\r
9990     ssh_sendok,\r
9991     ssh_ldisc,\r
9992     ssh_provide_ldisc,\r
9993     ssh_provide_logctx,\r
9994     ssh_unthrottle,\r
9995     ssh_cfg_info,\r
9996     "ssh",\r
9997     PROT_SSH,\r
9998     22\r
9999 };\r