OSDN Git Service

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