CPatch: New memory management
[TortoiseGit.git] / src / TortoisePlink / SSH.C
blob5157d99de9527acdf7b000054cc4b87cf873ba97
1 /*\r
2  * SSH backend.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include <stdarg.h>\r
8 #include <assert.h>\r
9 #include <limits.h>\r
10 #include <signal.h>\r
12 #include "putty.h"\r
13 #include "pageant.h" /* for AGENT_MAX_MSGLEN */\r
14 #include "tree234.h"\r
15 #include "storage.h"\r
16 #include "ssh.h"\r
17 #ifndef NO_GSSAPI\r
18 #include "sshgssc.h"\r
19 #include "sshgss.h"\r
20 #endif\r
22 #ifndef FALSE\r
23 #define FALSE 0\r
24 #endif\r
25 #ifndef TRUE\r
26 #define TRUE 1\r
27 #endif\r
29 /*\r
30  * Packet type contexts, so that ssh2_pkt_type can correctly decode\r
31  * the ambiguous type numbers back into the correct type strings.\r
32  */\r
33 typedef enum {\r
34     SSH2_PKTCTX_NOKEX,\r
35     SSH2_PKTCTX_DHGROUP,\r
36     SSH2_PKTCTX_DHGEX,\r
37     SSH2_PKTCTX_ECDHKEX,\r
38     SSH2_PKTCTX_RSAKEX\r
39 } Pkt_KCtx;\r
40 typedef enum {\r
41     SSH2_PKTCTX_NOAUTH,\r
42     SSH2_PKTCTX_PUBLICKEY,\r
43     SSH2_PKTCTX_PASSWORD,\r
44     SSH2_PKTCTX_GSSAPI,\r
45     SSH2_PKTCTX_KBDINTER\r
46 } Pkt_ACtx;\r
48 static const char *const ssh2_disconnect_reasons[] = {\r
49     NULL,\r
50     "host not allowed to connect",\r
51     "protocol error",\r
52     "key exchange failed",\r
53     "host authentication failed",\r
54     "MAC error",\r
55     "compression error",\r
56     "service not available",\r
57     "protocol version not supported",\r
58     "host key not verifiable",\r
59     "connection lost",\r
60     "by application",\r
61     "too many connections",\r
62     "auth cancelled by user",\r
63     "no more auth methods available",\r
64     "illegal user name",\r
65 };\r
67 /*\r
68  * Various remote-bug flags.\r
69  */\r
70 #define BUG_CHOKES_ON_SSH1_IGNORE                 1\r
71 #define BUG_SSH2_HMAC                             2\r
72 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD             4\r
73 #define BUG_CHOKES_ON_RSA                         8\r
74 #define BUG_SSH2_RSA_PADDING                     16\r
75 #define BUG_SSH2_DERIVEKEY                       32\r
76 #define BUG_SSH2_REKEY                           64\r
77 #define BUG_SSH2_PK_SESSIONID                   128\r
78 #define BUG_SSH2_MAXPKT                         256\r
79 #define BUG_CHOKES_ON_SSH2_IGNORE               512\r
80 #define BUG_CHOKES_ON_WINADJ                   1024\r
81 #define BUG_SENDS_LATE_REQUEST_REPLY           2048\r
82 #define BUG_SSH2_OLDGEX                        4096\r
84 #define DH_MIN_SIZE 1024\r
85 #define DH_MAX_SIZE 8192\r
87 /*\r
88  * Codes for terminal modes.\r
89  * Most of these are the same in SSH-1 and SSH-2.\r
90  * This list is derived from RFC 4254 and\r
91  * SSH-1 RFC-1.2.31.\r
92  */\r
93 static const struct ssh_ttymode {\r
94     const char* const mode;\r
95     int opcode;\r
96     enum { TTY_OP_CHAR, TTY_OP_BOOL } type;\r
97 } ssh_ttymodes[] = {\r
98     /* "V" prefix discarded for special characters relative to SSH specs */\r
99     { "INTR",         1, TTY_OP_CHAR },\r
100     { "QUIT",         2, TTY_OP_CHAR },\r
101     { "ERASE",        3, TTY_OP_CHAR },\r
102     { "KILL",         4, TTY_OP_CHAR },\r
103     { "EOF",          5, TTY_OP_CHAR },\r
104     { "EOL",          6, TTY_OP_CHAR },\r
105     { "EOL2",         7, TTY_OP_CHAR },\r
106     { "START",        8, TTY_OP_CHAR },\r
107     { "STOP",         9, TTY_OP_CHAR },\r
108     { "SUSP",        10, TTY_OP_CHAR },\r
109     { "DSUSP",       11, TTY_OP_CHAR },\r
110     { "REPRINT",     12, TTY_OP_CHAR },\r
111     { "WERASE",      13, TTY_OP_CHAR },\r
112     { "LNEXT",       14, TTY_OP_CHAR },\r
113     { "FLUSH",       15, TTY_OP_CHAR },\r
114     { "SWTCH",       16, TTY_OP_CHAR },\r
115     { "STATUS",      17, TTY_OP_CHAR },\r
116     { "DISCARD",     18, TTY_OP_CHAR },\r
117     { "IGNPAR",      30, TTY_OP_BOOL },\r
118     { "PARMRK",      31, TTY_OP_BOOL },\r
119     { "INPCK",       32, TTY_OP_BOOL },\r
120     { "ISTRIP",      33, TTY_OP_BOOL },\r
121     { "INLCR",       34, TTY_OP_BOOL },\r
122     { "IGNCR",       35, TTY_OP_BOOL },\r
123     { "ICRNL",       36, TTY_OP_BOOL },\r
124     { "IUCLC",       37, TTY_OP_BOOL },\r
125     { "IXON",        38, TTY_OP_BOOL },\r
126     { "IXANY",       39, TTY_OP_BOOL },\r
127     { "IXOFF",       40, TTY_OP_BOOL },\r
128     { "IMAXBEL",     41, TTY_OP_BOOL },\r
129     { "IUTF8",       42, TTY_OP_BOOL },\r
130     { "ISIG",        50, TTY_OP_BOOL },\r
131     { "ICANON",      51, TTY_OP_BOOL },\r
132     { "XCASE",       52, TTY_OP_BOOL },\r
133     { "ECHO",        53, TTY_OP_BOOL },\r
134     { "ECHOE",       54, TTY_OP_BOOL },\r
135     { "ECHOK",       55, TTY_OP_BOOL },\r
136     { "ECHONL",      56, TTY_OP_BOOL },\r
137     { "NOFLSH",      57, TTY_OP_BOOL },\r
138     { "TOSTOP",      58, TTY_OP_BOOL },\r
139     { "IEXTEN",      59, TTY_OP_BOOL },\r
140     { "ECHOCTL",     60, TTY_OP_BOOL },\r
141     { "ECHOKE",      61, TTY_OP_BOOL },\r
142     { "PENDIN",      62, TTY_OP_BOOL }, /* XXX is this a real mode? */\r
143     { "OPOST",       70, TTY_OP_BOOL },\r
144     { "OLCUC",       71, TTY_OP_BOOL },\r
145     { "ONLCR",       72, TTY_OP_BOOL },\r
146     { "OCRNL",       73, TTY_OP_BOOL },\r
147     { "ONOCR",       74, TTY_OP_BOOL },\r
148     { "ONLRET",      75, TTY_OP_BOOL },\r
149     { "CS7",         90, TTY_OP_BOOL },\r
150     { "CS8",         91, TTY_OP_BOOL },\r
151     { "PARENB",      92, TTY_OP_BOOL },\r
152     { "PARODD",      93, TTY_OP_BOOL }\r
153 };\r
155 /* Miscellaneous other tty-related constants. */\r
156 #define SSH_TTY_OP_END            0\r
157 /* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */\r
158 #define SSH1_TTY_OP_ISPEED      192\r
159 #define SSH1_TTY_OP_OSPEED      193\r
160 #define SSH2_TTY_OP_ISPEED      128\r
161 #define SSH2_TTY_OP_OSPEED      129\r
163 /* Helper functions for parsing tty-related config. */\r
164 static unsigned int ssh_tty_parse_specchar(char *s)\r
166     unsigned int ret;\r
167     if (*s) {\r
168         char *next = NULL;\r
169         ret = ctrlparse(s, &next);\r
170         if (!next) ret = s[0];\r
171     } else {\r
172         ret = 255; /* special value meaning "don't set" */\r
173     }\r
174     return ret;\r
176 static unsigned int ssh_tty_parse_boolean(char *s)\r
178     if (stricmp(s, "yes") == 0 ||\r
179         stricmp(s, "on") == 0 ||\r
180         stricmp(s, "true") == 0 ||\r
181         stricmp(s, "+") == 0)\r
182         return 1; /* true */\r
183     else if (stricmp(s, "no") == 0 ||\r
184              stricmp(s, "off") == 0 ||\r
185              stricmp(s, "false") == 0 ||\r
186              stricmp(s, "-") == 0)\r
187         return 0; /* false */\r
188     else\r
189         return (atoi(s) != 0);\r
192 #define translate(x) if (type == x) return #x\r
193 #define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x\r
194 #define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x\r
195 static const char *ssh1_pkt_type(int type)\r
197     translate(SSH1_MSG_DISCONNECT);\r
198     translate(SSH1_SMSG_PUBLIC_KEY);\r
199     translate(SSH1_CMSG_SESSION_KEY);\r
200     translate(SSH1_CMSG_USER);\r
201     translate(SSH1_CMSG_AUTH_RSA);\r
202     translate(SSH1_SMSG_AUTH_RSA_CHALLENGE);\r
203     translate(SSH1_CMSG_AUTH_RSA_RESPONSE);\r
204     translate(SSH1_CMSG_AUTH_PASSWORD);\r
205     translate(SSH1_CMSG_REQUEST_PTY);\r
206     translate(SSH1_CMSG_WINDOW_SIZE);\r
207     translate(SSH1_CMSG_EXEC_SHELL);\r
208     translate(SSH1_CMSG_EXEC_CMD);\r
209     translate(SSH1_SMSG_SUCCESS);\r
210     translate(SSH1_SMSG_FAILURE);\r
211     translate(SSH1_CMSG_STDIN_DATA);\r
212     translate(SSH1_SMSG_STDOUT_DATA);\r
213     translate(SSH1_SMSG_STDERR_DATA);\r
214     translate(SSH1_CMSG_EOF);\r
215     translate(SSH1_SMSG_EXIT_STATUS);\r
216     translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);\r
217     translate(SSH1_MSG_CHANNEL_OPEN_FAILURE);\r
218     translate(SSH1_MSG_CHANNEL_DATA);\r
219     translate(SSH1_MSG_CHANNEL_CLOSE);\r
220     translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);\r
221     translate(SSH1_SMSG_X11_OPEN);\r
222     translate(SSH1_CMSG_PORT_FORWARD_REQUEST);\r
223     translate(SSH1_MSG_PORT_OPEN);\r
224     translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING);\r
225     translate(SSH1_SMSG_AGENT_OPEN);\r
226     translate(SSH1_MSG_IGNORE);\r
227     translate(SSH1_CMSG_EXIT_CONFIRMATION);\r
228     translate(SSH1_CMSG_X11_REQUEST_FORWARDING);\r
229     translate(SSH1_CMSG_AUTH_RHOSTS_RSA);\r
230     translate(SSH1_MSG_DEBUG);\r
231     translate(SSH1_CMSG_REQUEST_COMPRESSION);\r
232     translate(SSH1_CMSG_AUTH_TIS);\r
233     translate(SSH1_SMSG_AUTH_TIS_CHALLENGE);\r
234     translate(SSH1_CMSG_AUTH_TIS_RESPONSE);\r
235     translate(SSH1_CMSG_AUTH_CCARD);\r
236     translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE);\r
237     translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);\r
238     return "unknown";\r
240 static const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx,\r
241                                  int type)\r
243     translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);\r
244     translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);\r
245     translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI);\r
246     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI);\r
247     translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI);\r
248     translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);\r
249     translate(SSH2_MSG_DISCONNECT);\r
250     translate(SSH2_MSG_IGNORE);\r
251     translate(SSH2_MSG_UNIMPLEMENTED);\r
252     translate(SSH2_MSG_DEBUG);\r
253     translate(SSH2_MSG_SERVICE_REQUEST);\r
254     translate(SSH2_MSG_SERVICE_ACCEPT);\r
255     translate(SSH2_MSG_KEXINIT);\r
256     translate(SSH2_MSG_NEWKEYS);\r
257     translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);\r
258     translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);\r
259     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX);\r
260     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);\r
261     translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);\r
262     translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);\r
263     translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);\r
264     translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);\r
265     translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);\r
266     translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);\r
267     translatek(SSH2_MSG_KEX_ECDH_INIT, SSH2_PKTCTX_ECDHKEX);\r
268     translatek(SSH2_MSG_KEX_ECDH_REPLY, SSH2_PKTCTX_ECDHKEX);\r
269     translate(SSH2_MSG_USERAUTH_REQUEST);\r
270     translate(SSH2_MSG_USERAUTH_FAILURE);\r
271     translate(SSH2_MSG_USERAUTH_SUCCESS);\r
272     translate(SSH2_MSG_USERAUTH_BANNER);\r
273     translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);\r
274     translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);\r
275     translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);\r
276     translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);\r
277     translate(SSH2_MSG_GLOBAL_REQUEST);\r
278     translate(SSH2_MSG_REQUEST_SUCCESS);\r
279     translate(SSH2_MSG_REQUEST_FAILURE);\r
280     translate(SSH2_MSG_CHANNEL_OPEN);\r
281     translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
282     translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
283     translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
284     translate(SSH2_MSG_CHANNEL_DATA);\r
285     translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);\r
286     translate(SSH2_MSG_CHANNEL_EOF);\r
287     translate(SSH2_MSG_CHANNEL_CLOSE);\r
288     translate(SSH2_MSG_CHANNEL_REQUEST);\r
289     translate(SSH2_MSG_CHANNEL_SUCCESS);\r
290     translate(SSH2_MSG_CHANNEL_FAILURE);\r
291     return "unknown";\r
293 #undef translate\r
294 #undef translatec\r
296 /* Enumeration values for fields in SSH-1 packets */\r
297 enum {\r
298     PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,\r
299 };\r
301 /*\r
302  * Coroutine mechanics for the sillier bits of the code. If these\r
303  * macros look impenetrable to you, you might find it helpful to\r
304  * read\r
305  * \r
306  *   https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\r
307  * \r
308  * which explains the theory behind these macros.\r
309  * \r
310  * In particular, if you are getting `case expression not constant'\r
311  * errors when building with MS Visual Studio, this is because MS's\r
312  * Edit and Continue debugging feature causes their compiler to\r
313  * violate ANSI C. To disable Edit and Continue debugging:\r
314  * \r
315  *  - right-click ssh.c in the FileView\r
316  *  - click Settings\r
317  *  - select the C/C++ tab and the General category\r
318  *  - under `Debug info:', select anything _other_ than `Program\r
319  *    Database for Edit and Continue'.\r
320  */\r
321 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;\r
322 #define crBeginState    crBegin(s->crLine)\r
323 #define crStateP(t, v)                          \\r
324     struct t *s;                                \\r
325     if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; }      \\r
326     s = (v);\r
327 #define crState(t)      crStateP(t, ssh->t)\r
328 #define crFinish(z)     } *crLine = 0; return (z); }\r
329 #define crFinishV       } *crLine = 0; return; }\r
330 #define crFinishFree(z) } sfree(s); return (z); }\r
331 #define crFinishFreeV   } sfree(s); return; }\r
332 #define crReturn(z)     \\r
333         do {\\r
334             *crLine =__LINE__; return (z); case __LINE__:;\\r
335         } while (0)\r
336 #define crReturnV       \\r
337         do {\\r
338             *crLine=__LINE__; return; case __LINE__:;\\r
339         } while (0)\r
340 #define crStop(z)       do{ *crLine = 0; return (z); }while(0)\r
341 #define crStopV         do{ *crLine = 0; return; }while(0)\r
342 #define crWaitUntil(c)  do { crReturn(0); } while (!(c))\r
343 #define crWaitUntilV(c) do { crReturnV; } while (!(c))\r
345 struct Packet;\r
347 static struct Packet *ssh1_pkt_init(int pkt_type);\r
348 static struct Packet *ssh2_pkt_init(int pkt_type);\r
349 static void ssh_pkt_ensure(struct Packet *, int length);\r
350 static void ssh_pkt_adddata(struct Packet *, const void *data, int len);\r
351 static void ssh_pkt_addbyte(struct Packet *, unsigned char value);\r
352 static void ssh2_pkt_addbool(struct Packet *, unsigned char value);\r
353 static void ssh_pkt_adduint32(struct Packet *, unsigned long value);\r
354 static void ssh_pkt_addstring_start(struct Packet *);\r
355 static void ssh_pkt_addstring_str(struct Packet *, const char *data);\r
356 static void ssh_pkt_addstring_data(struct Packet *, const char *data, int len);\r
357 static void ssh_pkt_addstring(struct Packet *, const char *data);\r
358 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);\r
359 static void ssh1_pkt_addmp(struct Packet *, Bignum b);\r
360 static void ssh2_pkt_addmp(struct Packet *, Bignum b);\r
361 static int ssh2_pkt_construct(Ssh, struct Packet *);\r
362 static void ssh2_pkt_send(Ssh, struct Packet *);\r
363 static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);\r
364 static int do_ssh1_login(Ssh ssh, const unsigned char *in, int inlen,\r
365                          struct Packet *pktin);\r
366 static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,\r
367                              struct Packet *pktin);\r
368 static void ssh_channel_init(struct ssh_channel *c);\r
369 static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin);\r
370 static void ssh_channel_got_eof(struct ssh_channel *c);\r
371 static void ssh2_channel_check_close(struct ssh_channel *c);\r
372 static void ssh_channel_close_local(struct ssh_channel *c, char const *reason);\r
373 static void ssh_channel_destroy(struct ssh_channel *c);\r
374 static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize);\r
375 static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin);\r
377 /*\r
378  * Buffer management constants. There are several of these for\r
379  * various different purposes:\r
380  * \r
381  *  - SSH1_BUFFER_LIMIT is the amount of backlog that must build up\r
382  *    on a local data stream before we throttle the whole SSH\r
383  *    connection (in SSH-1 only). Throttling the whole connection is\r
384  *    pretty drastic so we set this high in the hope it won't\r
385  *    happen very often.\r
386  * \r
387  *  - SSH_MAX_BACKLOG is the amount of backlog that must build up\r
388  *    on the SSH connection itself before we defensively throttle\r
389  *    _all_ local data streams. This is pretty drastic too (though\r
390  *    thankfully unlikely in SSH-2 since the window mechanism should\r
391  *    ensure that the server never has any need to throttle its end\r
392  *    of the connection), so we set this high as well.\r
393  * \r
394  *  - OUR_V2_WINSIZE is the default window size we present on SSH-2\r
395  *    channels.\r
396  *\r
397  *  - OUR_V2_BIGWIN is the window size we advertise for the only\r
398  *    channel in a simple connection.  It must be <= INT_MAX.\r
399  *\r
400  *  - OUR_V2_MAXPKT is the official "maximum packet size" we send\r
401  *    to the remote side. This actually has nothing to do with the\r
402  *    size of the _packet_, but is instead a limit on the amount\r
403  *    of data we're willing to receive in a single SSH2 channel\r
404  *    data message.\r
405  *\r
406  *  - OUR_V2_PACKETLIMIT is actually the maximum size of SSH\r
407  *    _packet_ we're prepared to cope with.  It must be a multiple\r
408  *    of the cipher block size, and must be at least 35000.\r
409  */\r
411 #define SSH1_BUFFER_LIMIT 32768\r
412 #define SSH_MAX_BACKLOG 32768\r
413 #define OUR_V2_WINSIZE 16384\r
414 #define OUR_V2_BIGWIN 0x7fffffff\r
415 #define OUR_V2_MAXPKT 0x4000UL\r
416 #define OUR_V2_PACKETLIMIT 0x9000UL\r
418 struct ssh_signkey_with_user_pref_id {\r
419     const struct ssh_signkey *alg;\r
420     int id;\r
421 };\r
422 const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = {\r
423     { &ssh_ecdsa_ed25519, HK_ED25519 },\r
424     { &ssh_ecdsa_nistp256, HK_ECDSA },\r
425     { &ssh_ecdsa_nistp384, HK_ECDSA },\r
426     { &ssh_ecdsa_nistp521, HK_ECDSA },\r
427     { &ssh_dss, HK_DSA },\r
428     { &ssh_rsa, HK_RSA },\r
429 };\r
431 const static struct ssh_mac *const macs[] = {\r
432     &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5\r
433 };\r
434 const static struct ssh_mac *const buggymacs[] = {\r
435     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5\r
436 };\r
438 static void *ssh_comp_none_init(void)\r
440     return NULL;\r
442 static void ssh_comp_none_cleanup(void *handle)\r
445 static int ssh_comp_none_block(void *handle, unsigned char *block, int len,\r
446                                unsigned char **outblock, int *outlen)\r
448     return 0;\r
450 static int ssh_comp_none_disable(void *handle)\r
452     return 0;\r
454 const static struct ssh_compress ssh_comp_none = {\r
455     "none", NULL,\r
456     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
457     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,\r
458     ssh_comp_none_disable, NULL\r
459 };\r
460 extern const struct ssh_compress ssh_zlib;\r
461 const static struct ssh_compress *const compressions[] = {\r
462     &ssh_zlib, &ssh_comp_none\r
463 };\r
465 enum {                                 /* channel types */\r
466     CHAN_MAINSESSION,\r
467     CHAN_X11,\r
468     CHAN_AGENT,\r
469     CHAN_SOCKDATA,\r
470     /*\r
471      * CHAN_SHARING indicates a channel which is tracked here on\r
472      * behalf of a connection-sharing downstream. We do almost nothing\r
473      * with these channels ourselves: all messages relating to them\r
474      * get thrown straight to sshshare.c and passed on almost\r
475      * unmodified to downstream.\r
476      */\r
477     CHAN_SHARING,\r
478     /*\r
479      * CHAN_ZOMBIE is used to indicate a channel for which we've\r
480      * already destroyed the local data source: for instance, if a\r
481      * forwarded port experiences a socket error on the local side, we\r
482      * immediately destroy its local socket and turn the SSH channel\r
483      * into CHAN_ZOMBIE.\r
484      */\r
485     CHAN_ZOMBIE\r
486 };\r
488 typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);\r
489 typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);\r
490 typedef void (*cchandler_fn_t)(struct ssh_channel *, struct Packet *, void *);\r
492 /*\r
493  * Each channel has a queue of outstanding CHANNEL_REQUESTS and their\r
494  * handlers.\r
495  */\r
496 struct outstanding_channel_request {\r
497     cchandler_fn_t handler;\r
498     void *ctx;\r
499     struct outstanding_channel_request *next;\r
500 };\r
502 /*\r
503  * 2-3-4 tree storing channels.\r
504  */\r
505 struct ssh_channel {\r
506     Ssh ssh;                           /* pointer back to main context */\r
507     unsigned remoteid, localid;\r
508     int type;\r
509     /* True if we opened this channel but server hasn't confirmed. */\r
510     int halfopen;\r
511     /*\r
512      * In SSH-1, this value contains four bits:\r
513      * \r
514      *   1   We have sent SSH1_MSG_CHANNEL_CLOSE.\r
515      *   2   We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
516      *   4   We have received SSH1_MSG_CHANNEL_CLOSE.\r
517      *   8   We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.\r
518      * \r
519      * A channel is completely finished with when all four bits are set.\r
520      *\r
521      * In SSH-2, the four bits mean:\r
522      *\r
523      *   1   We have sent SSH2_MSG_CHANNEL_EOF.\r
524      *   2   We have sent SSH2_MSG_CHANNEL_CLOSE.\r
525      *   4   We have received SSH2_MSG_CHANNEL_EOF.\r
526      *   8   We have received SSH2_MSG_CHANNEL_CLOSE.\r
527      *\r
528      * A channel is completely finished with when we have both sent\r
529      * and received CLOSE.\r
530      *\r
531      * The symbolic constants below use the SSH-2 terminology, which\r
532      * is a bit confusing in SSH-1, but we have to use _something_.\r
533      */\r
534 #define CLOSES_SENT_EOF    1\r
535 #define CLOSES_SENT_CLOSE  2\r
536 #define CLOSES_RCVD_EOF    4\r
537 #define CLOSES_RCVD_CLOSE  8\r
538     int closes;\r
540     /*\r
541      * This flag indicates that an EOF is pending on the outgoing side\r
542      * of the channel: that is, wherever we're getting the data for\r
543      * this channel has sent us some data followed by EOF. We can't\r
544      * actually send the EOF until we've finished sending the data, so\r
545      * we set this flag instead to remind us to do so once our buffer\r
546      * is clear.\r
547      */\r
548     int pending_eof;\r
550     /*\r
551      * True if this channel is causing the underlying connection to be\r
552      * throttled.\r
553      */\r
554     int throttling_conn;\r
555     union {\r
556         struct ssh2_data_channel {\r
557             bufchain outbuffer;\r
558             unsigned remwindow, remmaxpkt;\r
559             /* locwindow is signed so we can cope with excess data. */\r
560             int locwindow, locmaxwin;\r
561             /*\r
562              * remlocwin is the amount of local window that we think\r
563              * the remote end had available to it after it sent the\r
564              * last data packet or window adjust ack.\r
565              */\r
566             int remlocwin;\r
567             /*\r
568              * These store the list of channel requests that haven't\r
569              * been acked.\r
570              */\r
571             struct outstanding_channel_request *chanreq_head, *chanreq_tail;\r
572             enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state;\r
573         } v2;\r
574     } v;\r
575     union {\r
576         struct ssh_agent_channel {\r
577             bufchain inbuffer;\r
578             agent_pending_query *pending;\r
579         } a;\r
580         struct ssh_x11_channel {\r
581             struct X11Connection *xconn;\r
582             int initial;\r
583         } x11;\r
584         struct ssh_pfd_channel {\r
585             struct PortForwarding *pf;\r
586         } pfd;\r
587         struct ssh_sharing_channel {\r
588             void *ctx;\r
589         } sharing;\r
590     } u;\r
591 };\r
593 /*\r
594  * 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2\r
595  * use this structure in different ways, reflecting SSH-2's\r
596  * altogether saner approach to port forwarding.\r
597  * \r
598  * In SSH-1, you arrange a remote forwarding by sending the server\r
599  * the remote port number, and the local destination host:port.\r
600  * When a connection comes in, the server sends you back that\r
601  * host:port pair, and you connect to it. This is a ready-made\r
602  * security hole if you're not on the ball: a malicious server\r
603  * could send you back _any_ host:port pair, so if you trustingly\r
604  * connect to the address it gives you then you've just opened the\r
605  * entire inside of your corporate network just by connecting\r
606  * through it to a dodgy SSH server. Hence, we must store a list of\r
607  * host:port pairs we _are_ trying to forward to, and reject a\r
608  * connection request from the server if it's not in the list.\r
609  * \r
610  * In SSH-2, each side of the connection minds its own business and\r
611  * doesn't send unnecessary information to the other. You arrange a\r
612  * remote forwarding by sending the server just the remote port\r
613  * number. When a connection comes in, the server tells you which\r
614  * of its ports was connected to; and _you_ have to remember what\r
615  * local host:port pair went with that port number.\r
616  * \r
617  * Hence, in SSH-1 this structure is indexed by destination\r
618  * host:port pair, whereas in SSH-2 it is indexed by source port.\r
619  */\r
620 struct ssh_portfwd; /* forward declaration */\r
622 struct ssh_rportfwd {\r
623     unsigned sport, dport;\r
624     char *shost, *dhost;\r
625     char *sportdesc;\r
626     void *share_ctx;\r
627     struct ssh_portfwd *pfrec;\r
628 };\r
630 static void free_rportfwd(struct ssh_rportfwd *pf)\r
632     if (pf) {\r
633         sfree(pf->sportdesc);\r
634         sfree(pf->shost);\r
635         sfree(pf->dhost);\r
636         sfree(pf);\r
637     }\r
640 /*\r
641  * Separately to the rportfwd tree (which is for looking up port\r
642  * open requests from the server), a tree of _these_ structures is\r
643  * used to keep track of all the currently open port forwardings,\r
644  * so that we can reconfigure in mid-session if the user requests\r
645  * it.\r
646  */\r
647 struct ssh_portfwd {\r
648     enum { DESTROY, KEEP, CREATE } status;\r
649     int type;\r
650     unsigned sport, dport;\r
651     char *saddr, *daddr;\r
652     char *sserv, *dserv;\r
653     struct ssh_rportfwd *remote;\r
654     int addressfamily;\r
655     struct PortListener *local;\r
656 };\r
657 #define free_portfwd(pf) ( \\r
658     ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \\r
659              sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )\r
661 struct Packet {\r
662     long length;            /* length of packet: see below */\r
663     long forcepad;          /* SSH-2: force padding to at least this length */\r
664     int type;               /* only used for incoming packets */\r
665     unsigned long sequence; /* SSH-2 incoming sequence number */\r
666     unsigned char *data;    /* allocated storage */\r
667     unsigned char *body;    /* offset of payload within `data' */\r
668     long savedpos;          /* dual-purpose saved packet position: see below */\r
669     long maxlen;            /* amount of storage allocated for `data' */\r
670     long encrypted_len;     /* for SSH-2 total-size counting */\r
672     /*\r
673      * A note on the 'length' and 'savedpos' fields above.\r
674      *\r
675      * Incoming packets are set up so that pkt->length is measured\r
676      * relative to pkt->body, which itself points to a few bytes after\r
677      * pkt->data (skipping some uninteresting header fields including\r
678      * the packet type code). The ssh_pkt_get* functions all expect\r
679      * this setup, and they also use pkt->savedpos to indicate how far\r
680      * through the packet being decoded they've got - and that, too,\r
681      * is an offset from pkt->body rather than pkt->data.\r
682      *\r
683      * During construction of an outgoing packet, however, pkt->length\r
684      * is measured relative to the base pointer pkt->data, and\r
685      * pkt->body is not really used for anything until the packet is\r
686      * ready for sending. In this mode, pkt->savedpos is reused as a\r
687      * temporary variable by the addstring functions, which write out\r
688      * a string length field and then keep going back and updating it\r
689      * as more data is appended to the subsequent string data field;\r
690      * pkt->savedpos stores the offset (again relative to pkt->data)\r
691      * of the start of the string data field.\r
692      */\r
694     /* Extra metadata used in SSH packet logging mode, allowing us to\r
695      * log in the packet header line that the packet came from a\r
696      * connection-sharing downstream and what if anything unusual was\r
697      * done to it. The additional_log_text field is expected to be a\r
698      * static string - it will not be freed. */\r
699     unsigned downstream_id;\r
700     const char *additional_log_text;\r
701 };\r
703 static void ssh1_protocol(Ssh ssh, const void *vin, int inlen,\r
704                           struct Packet *pktin);\r
705 static void ssh2_protocol(Ssh ssh, const void *vin, int inlen,\r
706                           struct Packet *pktin);\r
707 static void ssh2_bare_connection_protocol(Ssh ssh, const void *vin, int inlen,\r
708                                           struct Packet *pktin);\r
709 static void ssh1_protocol_setup(Ssh ssh);\r
710 static void ssh2_protocol_setup(Ssh ssh);\r
711 static void ssh2_bare_connection_protocol_setup(Ssh ssh);\r
712 static void ssh_size(void *handle, int width, int height);\r
713 static void ssh_special(void *handle, Telnet_Special);\r
714 static int ssh2_try_send(struct ssh_channel *c);\r
715 static int ssh_send_channel_data(struct ssh_channel *c,\r
716                                  const char *buf, int len);\r
717 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);\r
718 static void ssh2_set_window(struct ssh_channel *c, int newwin);\r
719 static int ssh_sendbuffer(void *handle);\r
720 static int ssh_do_close(Ssh ssh, int notify_exit);\r
721 static unsigned long ssh_pkt_getuint32(struct Packet *pkt);\r
722 static int ssh2_pkt_getbool(struct Packet *pkt);\r
723 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);\r
724 static void ssh2_timer(void *ctx, unsigned long now);\r
725 static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,\r
726                               struct Packet *pktin);\r
727 static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin);\r
729 struct rdpkt1_state_tag {\r
730     long len, pad, biglen, to_read;\r
731     unsigned long realcrc, gotcrc;\r
732     unsigned char *p;\r
733     int i;\r
734     int chunk;\r
735     struct Packet *pktin;\r
736 };\r
738 struct rdpkt2_state_tag {\r
739     long len, pad, payload, packetlen, maclen;\r
740     int i;\r
741     int cipherblk;\r
742     unsigned long incoming_sequence;\r
743     struct Packet *pktin;\r
744 };\r
746 struct rdpkt2_bare_state_tag {\r
747     char length[4];\r
748     long packetlen;\r
749     int i;\r
750     unsigned long incoming_sequence;\r
751     struct Packet *pktin;\r
752 };\r
754 struct queued_handler;\r
755 struct queued_handler {\r
756     int msg1, msg2;\r
757     chandler_fn_t handler;\r
758     void *ctx;\r
759     struct queued_handler *next;\r
760 };\r
762 struct ssh_tag {\r
763     const struct plug_function_table *fn;\r
764     /* the above field _must_ be first in the structure */\r
766     char *v_c, *v_s;\r
767     void *exhash;\r
769     Socket s;\r
771     void *ldisc;\r
772     void *logctx;\r
774     unsigned char session_key[32];\r
775     int v1_compressing;\r
776     int v1_remote_protoflags;\r
777     int v1_local_protoflags;\r
778     int agentfwd_enabled;\r
779     int X11_fwd_enabled;\r
780     int remote_bugs;\r
781     const struct ssh_cipher *cipher;\r
782     void *v1_cipher_ctx;\r
783     void *crcda_ctx;\r
784     const struct ssh2_cipher *cscipher, *sccipher;\r
785     void *cs_cipher_ctx, *sc_cipher_ctx;\r
786     const struct ssh_mac *csmac, *scmac;\r
787     int csmac_etm, scmac_etm;\r
788     void *cs_mac_ctx, *sc_mac_ctx;\r
789     const struct ssh_compress *cscomp, *sccomp;\r
790     void *cs_comp_ctx, *sc_comp_ctx;\r
791     const struct ssh_kex *kex;\r
792     const struct ssh_signkey *hostkey;\r
793     char *hostkey_str; /* string representation, for easy checking in rekeys */\r
794     unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN];\r
795     int v2_session_id_len;\r
796     void *kex_ctx;\r
798     int bare_connection;\r
799     int attempting_connshare;\r
800     void *connshare;\r
802     char *savedhost;\r
803     int savedport;\r
804     int send_ok;\r
805     int echoing, editing;\r
807     int session_started;\r
808     void *frontend;\r
810     int ospeed, ispeed;                /* temporaries */\r
811     int term_width, term_height;\r
813     tree234 *channels;                 /* indexed by local id */\r
814     struct ssh_channel *mainchan;      /* primary session channel */\r
815     int ncmode;                        /* is primary channel direct-tcpip? */\r
816     int exitcode;\r
817     int close_expected;\r
818     int clean_exit;\r
820     tree234 *rportfwds, *portfwds;\r
822     enum {\r
823         SSH_STATE_PREPACKET,\r
824         SSH_STATE_BEFORE_SIZE,\r
825         SSH_STATE_INTERMED,\r
826         SSH_STATE_SESSION,\r
827         SSH_STATE_CLOSED\r
828     } state;\r
830     int size_needed, eof_needed;\r
831     int sent_console_eof;\r
832     int got_pty;           /* affects EOF behaviour on main channel */\r
834     struct Packet **queue;\r
835     int queuelen, queuesize;\r
836     int queueing;\r
837     unsigned char *deferred_send_data;\r
838     int deferred_len, deferred_size;\r
840     /*\r
841      * Gross hack: pscp will try to start SFTP but fall back to\r
842      * scp1 if that fails. This variable is the means by which\r
843      * scp.c can reach into the SSH code and find out which one it\r
844      * got.\r
845      */\r
846     int fallback_cmd;\r
848     bufchain banner;    /* accumulates banners during do_ssh2_authconn */\r
850     Pkt_KCtx pkt_kctx;\r
851     Pkt_ACtx pkt_actx;\r
853     struct X11Display *x11disp;\r
854     struct X11FakeAuth *x11auth;\r
855     tree234 *x11authtree;\r
857     int version;\r
858     int conn_throttle_count;\r
859     int overall_bufsize;\r
860     int throttled_all;\r
861     int v1_stdout_throttling;\r
862     unsigned long v2_outgoing_sequence;\r
864     int ssh1_rdpkt_crstate;\r
865     int ssh2_rdpkt_crstate;\r
866     int ssh2_bare_rdpkt_crstate;\r
867     int ssh_gotdata_crstate;\r
868     int do_ssh1_connection_crstate;\r
870     void *do_ssh_init_state;\r
871     void *do_ssh1_login_state;\r
872     void *do_ssh2_transport_state;\r
873     void *do_ssh2_authconn_state;\r
874     void *do_ssh_connection_init_state;\r
876     struct rdpkt1_state_tag rdpkt1_state;\r
877     struct rdpkt2_state_tag rdpkt2_state;\r
878     struct rdpkt2_bare_state_tag rdpkt2_bare_state;\r
880     /* SSH-1 and SSH-2 use this for different things, but both use it */\r
881     int protocol_initial_phase_done;\r
883     void (*protocol) (Ssh ssh, const void *vin, int inlen,\r
884                       struct Packet *pkt);\r
885     struct Packet *(*s_rdpkt) (Ssh ssh, const unsigned char **data,\r
886                                int *datalen);\r
887     int (*do_ssh_init)(Ssh ssh, unsigned char c);\r
889     /*\r
890      * We maintain our own copy of a Conf structure here. That way,\r
891      * when we're passed a new one for reconfiguration, we can check\r
892      * the differences and potentially reconfigure port forwardings\r
893      * etc in mid-session.\r
894      */\r
895     Conf *conf;\r
897     /*\r
898      * Values cached out of conf so as to avoid the tree234 lookup\r
899      * cost every time they're used.\r
900      */\r
901     int logomitdata;\r
903     /*\r
904      * Dynamically allocated username string created during SSH\r
905      * login. Stored in here rather than in the coroutine state so\r
906      * that it'll be reliably freed if we shut down the SSH session\r
907      * at some unexpected moment.\r
908      */\r
909     char *username;\r
911     /*\r
912      * Used to transfer data back from async callbacks.\r
913      */\r
914     void *agent_response;\r
915     int agent_response_len;\r
916     int user_response;\r
918     /*\r
919      * The SSH connection can be set as `frozen', meaning we are\r
920      * not currently accepting incoming data from the network. This\r
921      * is slightly more serious than setting the _socket_ as\r
922      * frozen, because we may already have had data passed to us\r
923      * from the network which we need to delay processing until\r
924      * after the freeze is lifted, so we also need a bufchain to\r
925      * store that data.\r
926      */\r
927     int frozen;\r
928     bufchain queued_incoming_data;\r
930     /*\r
931      * Dispatch table for packet types that we may have to deal\r
932      * with at any time.\r
933      */\r
934     handler_fn_t packet_dispatch[256];\r
936     /*\r
937      * Queues of one-off handler functions for success/failure\r
938      * indications from a request.\r
939      */\r
940     struct queued_handler *qhead, *qtail;\r
941     handler_fn_t q_saved_handler1, q_saved_handler2;\r
943     /*\r
944      * This module deals with sending keepalives.\r
945      */\r
946     Pinger pinger;\r
948     /*\r
949      * Track incoming and outgoing data sizes and time, for\r
950      * size-based rekeys.\r
951      */\r
952     unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;\r
953     unsigned long max_data_size;\r
954     int kex_in_progress;\r
955     unsigned long next_rekey, last_rekey;\r
956     const char *deferred_rekey_reason;\r
958     /*\r
959      * Fully qualified host name, which we need if doing GSSAPI.\r
960      */\r
961     char *fullhostname;\r
963 #ifndef NO_GSSAPI\r
964     /*\r
965      * GSSAPI libraries for this session.\r
966      */\r
967     struct ssh_gss_liblist *gsslibs;\r
968 #endif\r
970     /*\r
971      * The last list returned from get_specials.\r
972      */\r
973     struct telnet_special *specials;\r
975     /*\r
976      * List of host key algorithms for which we _don't_ have a stored\r
977      * host key. These are indices into the main hostkey_algs[] array\r
978      */\r
979     int uncert_hostkeys[lenof(hostkey_algs)];\r
980     int n_uncert_hostkeys;\r
982     /*\r
983      * Flag indicating that the current rekey is intended to finish\r
984      * with a newly cross-certified host key.\r
985      */\r
986     int cross_certifying;\r
988     /*\r
989      * Any asynchronous query to our SSH agent that we might have in\r
990      * flight from the main authentication loop. (Queries from\r
991      * agent-forwarding channels live in their channel structure.)\r
992      */\r
993     agent_pending_query *auth_agent_query;\r
994 };\r
996 static const char *ssh_pkt_type(Ssh ssh, int type)\r
998     if (ssh->version == 1)\r
999         return ssh1_pkt_type(type);\r
1000     else\r
1001         return ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, type);\r
1004 #define logevent(s) logevent(ssh->frontend, s)\r
1006 /* logevent, only printf-formatted. */\r
1007 static void logeventf(Ssh ssh, const char *fmt, ...)\r
1009     va_list ap;\r
1010     char *buf;\r
1012     va_start(ap, fmt);\r
1013     buf = dupvprintf(fmt, ap);\r
1014     va_end(ap);\r
1015     logevent(buf);\r
1016     sfree(buf);\r
1019 static void bomb_out(Ssh ssh, char *text)\r
1021     ssh_do_close(ssh, FALSE);\r
1022     logevent(text);\r
1023     connection_fatal(ssh->frontend, "%s", text);\r
1024     sfree(text);\r
1027 #define bombout(msg) bomb_out(ssh, dupprintf msg)\r
1029 /* Helper function for common bits of parsing ttymodes. */\r
1030 static void parse_ttymodes(Ssh ssh,\r
1031                            void (*do_mode)(void *data,\r
1032                                            const struct ssh_ttymode *mode,\r
1033                                            char *val),\r
1034                            void *data)\r
1036     int i;\r
1037     const struct ssh_ttymode *mode;\r
1038     char *val;\r
1040     for (i = 0; i < lenof(ssh_ttymodes); i++) {\r
1041         mode = ssh_ttymodes + i;\r
1042         /* Every mode known to the current version of the code should be\r
1043          * mentioned; this was ensured when settings were loaded. */\r
1044         val = conf_get_str_str(ssh->conf, CONF_ttymodes, mode->mode);\r
1046         /*\r
1047          * val[0] can be\r
1048          *  - 'V', indicating that an explicit value follows it;\r
1049          *  - 'A', indicating that we should pass the value through from\r
1050          *    the local environment via get_ttymode; or\r
1051          *  - 'N', indicating that we should explicitly not send this\r
1052          *    mode.\r
1053          */\r
1054         if (val[0] == 'A') {\r
1055             val = get_ttymode(ssh->frontend, mode->mode);\r
1056             if (val) {\r
1057                 do_mode(data, mode, val);\r
1058                 sfree(val);\r
1059             }\r
1060         } else if (val[0] == 'V') {\r
1061             do_mode(data, mode, val + 1);              /* skip the 'V' */\r
1062         } /* else 'N', or something from the future we don't understand */\r
1063     }\r
1066 static int ssh_channelcmp(void *av, void *bv)\r
1068     struct ssh_channel *a = (struct ssh_channel *) av;\r
1069     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1070     if (a->localid < b->localid)\r
1071         return -1;\r
1072     if (a->localid > b->localid)\r
1073         return +1;\r
1074     return 0;\r
1076 static int ssh_channelfind(void *av, void *bv)\r
1078     unsigned *a = (unsigned *) av;\r
1079     struct ssh_channel *b = (struct ssh_channel *) bv;\r
1080     if (*a < b->localid)\r
1081         return -1;\r
1082     if (*a > b->localid)\r
1083         return +1;\r
1084     return 0;\r
1087 static int ssh_rportcmp_ssh1(void *av, void *bv)\r
1089     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1090     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1091     int i;\r
1092     if ( (i = strcmp(a->dhost, b->dhost)) != 0)\r
1093         return i < 0 ? -1 : +1;\r
1094     if (a->dport > b->dport)\r
1095         return +1;\r
1096     if (a->dport < b->dport)\r
1097         return -1;\r
1098     return 0;\r
1101 static int ssh_rportcmp_ssh2(void *av, void *bv)\r
1103     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;\r
1104     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;\r
1105     int i;\r
1106     if ( (i = strcmp(a->shost, b->shost)) != 0)\r
1107         return i < 0 ? -1 : +1;\r
1108     if (a->sport > b->sport)\r
1109         return +1;\r
1110     if (a->sport < b->sport)\r
1111         return -1;\r
1112     return 0;\r
1115 /*\r
1116  * Special form of strcmp which can cope with NULL inputs. NULL is\r
1117  * defined to sort before even the empty string.\r
1118  */\r
1119 static int nullstrcmp(const char *a, const char *b)\r
1121     if (a == NULL && b == NULL)\r
1122         return 0;\r
1123     if (a == NULL)\r
1124         return -1;\r
1125     if (b == NULL)\r
1126         return +1;\r
1127     return strcmp(a, b);\r
1130 static int ssh_portcmp(void *av, void *bv)\r
1132     struct ssh_portfwd *a = (struct ssh_portfwd *) av;\r
1133     struct ssh_portfwd *b = (struct ssh_portfwd *) bv;\r
1134     int i;\r
1135     if (a->type > b->type)\r
1136         return +1;\r
1137     if (a->type < b->type)\r
1138         return -1;\r
1139     if (a->addressfamily > b->addressfamily)\r
1140         return +1;\r
1141     if (a->addressfamily < b->addressfamily)\r
1142         return -1;\r
1143     if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)\r
1144         return i < 0 ? -1 : +1;\r
1145     if (a->sport > b->sport)\r
1146         return +1;\r
1147     if (a->sport < b->sport)\r
1148         return -1;\r
1149     if (a->type != 'D') {\r
1150         if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)\r
1151             return i < 0 ? -1 : +1;\r
1152         if (a->dport > b->dport)\r
1153             return +1;\r
1154         if (a->dport < b->dport)\r
1155             return -1;\r
1156     }\r
1157     return 0;\r
1160 static int alloc_channel_id(Ssh ssh)\r
1162     const unsigned CHANNEL_NUMBER_OFFSET = 256;\r
1163     unsigned low, high, mid;\r
1164     int tsize;\r
1165     struct ssh_channel *c;\r
1167     /*\r
1168      * First-fit allocation of channel numbers: always pick the\r
1169      * lowest unused one. To do this, binary-search using the\r
1170      * counted B-tree to find the largest channel ID which is in a\r
1171      * contiguous sequence from the beginning. (Precisely\r
1172      * everything in that sequence must have ID equal to its tree\r
1173      * index plus CHANNEL_NUMBER_OFFSET.)\r
1174      */\r
1175     tsize = count234(ssh->channels);\r
1177     low = -1;\r
1178     high = tsize;\r
1179     while (high - low > 1) {\r
1180         mid = (high + low) / 2;\r
1181         c = index234(ssh->channels, mid);\r
1182         if (c->localid == mid + CHANNEL_NUMBER_OFFSET)\r
1183             low = mid;                 /* this one is fine */\r
1184         else\r
1185             high = mid;                /* this one is past it */\r
1186     }\r
1187     /*\r
1188      * Now low points to either -1, or the tree index of the\r
1189      * largest ID in the initial sequence.\r
1190      */\r
1191     {\r
1192         unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;\r
1193         assert(NULL == find234(ssh->channels, &i, ssh_channelfind));\r
1194     }\r
1195     return low + 1 + CHANNEL_NUMBER_OFFSET;\r
1198 static void c_write_stderr(int trusted, const char *buf, int len)\r
1200     int i;\r
1201     for (i = 0; i < len; i++)\r
1202         if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60)))\r
1203             fputc(buf[i], stderr);\r
1206 static void c_write(Ssh ssh, const char *buf, int len)\r
1208     if (flags & FLAG_STDERR)\r
1209         c_write_stderr(1, buf, len);\r
1210     else\r
1211         from_backend(ssh->frontend, 1, buf, len);\r
1214 static void c_write_untrusted(Ssh ssh, const char *buf, int len)\r
1216     if (flags & FLAG_STDERR)\r
1217         c_write_stderr(0, buf, len);\r
1218     else\r
1219         from_backend_untrusted(ssh->frontend, buf, len);\r
1222 static void c_write_str(Ssh ssh, const char *buf)\r
1224     c_write(ssh, buf, strlen(buf));\r
1227 static void ssh_free_packet(struct Packet *pkt)\r
1229     sfree(pkt->data);\r
1230     sfree(pkt);\r
1232 static struct Packet *ssh_new_packet(void)\r
1234     struct Packet *pkt = snew(struct Packet);\r
1236     pkt->body = pkt->data = NULL;\r
1237     pkt->maxlen = 0;\r
1239     return pkt;\r
1242 static void ssh1_log_incoming_packet(Ssh ssh, struct Packet *pkt)\r
1244     int nblanks = 0;\r
1245     struct logblank_t blanks[4];\r
1246     char *str;\r
1247     int slen;\r
1249     pkt->savedpos = 0;\r
1251     if (ssh->logomitdata &&\r
1252         (pkt->type == SSH1_SMSG_STDOUT_DATA ||\r
1253          pkt->type == SSH1_SMSG_STDERR_DATA ||\r
1254          pkt->type == SSH1_MSG_CHANNEL_DATA)) {\r
1255         /* "Session data" packets - omit the data string. */\r
1256         if (pkt->type == SSH1_MSG_CHANNEL_DATA)\r
1257             ssh_pkt_getuint32(pkt);    /* skip channel id */\r
1258         blanks[nblanks].offset = pkt->savedpos + 4;\r
1259         blanks[nblanks].type = PKTLOG_OMIT;\r
1260         ssh_pkt_getstring(pkt, &str, &slen);\r
1261         if (str) {\r
1262             blanks[nblanks].len = slen;\r
1263             nblanks++;\r
1264         }\r
1265     }\r
1266     log_packet(ssh->logctx, PKT_INCOMING, pkt->type,\r
1267                ssh1_pkt_type(pkt->type),\r
1268                pkt->body, pkt->length, nblanks, blanks, NULL,\r
1269                0, NULL);\r
1272 static void ssh1_log_outgoing_packet(Ssh ssh, struct Packet *pkt)\r
1274     int nblanks = 0;\r
1275     struct logblank_t blanks[4];\r
1276     char *str;\r
1277     int slen;\r
1279     /*\r
1280      * For outgoing packets, pkt->length represents the length of the\r
1281      * whole packet starting at pkt->data (including some header), and\r
1282      * pkt->body refers to the point within that where the log-worthy\r
1283      * payload begins. However, incoming packets expect pkt->length to\r
1284      * represent only the payload length (that is, it's measured from\r
1285      * pkt->body not from pkt->data). Temporarily adjust our outgoing\r
1286      * packet to conform to the incoming-packet semantics, so that we\r
1287      * can analyse it with the ssh_pkt_get functions.\r
1288      */\r
1289     pkt->length -= (pkt->body - pkt->data);\r
1290     pkt->savedpos = 0;\r
1292     if (ssh->logomitdata &&\r
1293         (pkt->type == SSH1_CMSG_STDIN_DATA ||\r
1294          pkt->type == SSH1_MSG_CHANNEL_DATA)) {\r
1295         /* "Session data" packets - omit the data string. */\r
1296         if (pkt->type == SSH1_MSG_CHANNEL_DATA)\r
1297             ssh_pkt_getuint32(pkt);    /* skip channel id */\r
1298         blanks[nblanks].offset = pkt->savedpos + 4;\r
1299         blanks[nblanks].type = PKTLOG_OMIT;\r
1300         ssh_pkt_getstring(pkt, &str, &slen);\r
1301         if (str) {\r
1302             blanks[nblanks].len = slen;\r
1303             nblanks++;\r
1304         }\r
1305     }\r
1307     if ((pkt->type == SSH1_CMSG_AUTH_PASSWORD ||\r
1308          pkt->type == SSH1_CMSG_AUTH_TIS_RESPONSE ||\r
1309          pkt->type == SSH1_CMSG_AUTH_CCARD_RESPONSE) &&\r
1310         conf_get_int(ssh->conf, CONF_logomitpass)) {\r
1311         /* If this is a password or similar packet, blank the password(s). */\r
1312         blanks[nblanks].offset = 0;\r
1313         blanks[nblanks].len = pkt->length;\r
1314         blanks[nblanks].type = PKTLOG_BLANK;\r
1315         nblanks++;\r
1316     } else if (pkt->type == SSH1_CMSG_X11_REQUEST_FORWARDING &&\r
1317                conf_get_int(ssh->conf, CONF_logomitpass)) {\r
1318         /*\r
1319          * If this is an X forwarding request packet, blank the fake\r
1320          * auth data.\r
1321          *\r
1322          * Note that while we blank the X authentication data here, we\r
1323          * don't take any special action to blank the start of an X11\r
1324          * channel, so using MIT-MAGIC-COOKIE-1 and actually opening\r
1325          * an X connection without having session blanking enabled is\r
1326          * likely to leak your cookie into the log.\r
1327          */\r
1328         pkt->savedpos = 0;\r
1329         ssh_pkt_getstring(pkt, &str, &slen);\r
1330         blanks[nblanks].offset = pkt->savedpos;\r
1331         blanks[nblanks].type = PKTLOG_BLANK;\r
1332         ssh_pkt_getstring(pkt, &str, &slen);\r
1333         if (str) {\r
1334             blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;\r
1335             nblanks++;\r
1336         }\r
1337     }\r
1339     log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],\r
1340                ssh1_pkt_type(pkt->data[12]),\r
1341                pkt->body, pkt->length,\r
1342                nblanks, blanks, NULL, 0, NULL);\r
1344     /*\r
1345      * Undo the above adjustment of pkt->length, to put the packet\r
1346      * back in the state we found it.\r
1347      */\r
1348     pkt->length += (pkt->body - pkt->data);\r
1351 /*\r
1352  * Collect incoming data in the incoming packet buffer.\r
1353  * Decipher and verify the packet when it is completely read.\r
1354  * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.\r
1355  * Update the *data and *datalen variables.\r
1356  * Return a Packet structure when a packet is completed.\r
1357  */\r
1358 static struct Packet *ssh1_rdpkt(Ssh ssh, const unsigned char **data,\r
1359                                  int *datalen)\r
1361     struct rdpkt1_state_tag *st = &ssh->rdpkt1_state;\r
1363     crBegin(ssh->ssh1_rdpkt_crstate);\r
1365     st->pktin = ssh_new_packet();\r
1367     st->pktin->type = 0;\r
1368     st->pktin->length = 0;\r
1370     for (st->i = st->len = 0; st->i < 4; st->i++) {\r
1371         while ((*datalen) == 0)\r
1372             crReturn(NULL);\r
1373         st->len = (st->len << 8) + **data;\r
1374         (*data)++, (*datalen)--;\r
1375     }\r
1377     st->pad = 8 - (st->len % 8);\r
1378     st->biglen = st->len + st->pad;\r
1379     st->pktin->length = st->len - 5;\r
1381     if (st->biglen < 0) {\r
1382         bombout(("Extremely large packet length from server suggests"\r
1383                  " data stream corruption"));\r
1384         ssh_free_packet(st->pktin);\r
1385         crStop(NULL);\r
1386     }\r
1388     st->pktin->maxlen = st->biglen;\r
1389     st->pktin->data = snewn(st->biglen + APIEXTRA, unsigned char);\r
1391     st->to_read = st->biglen;\r
1392     st->p = st->pktin->data;\r
1393     while (st->to_read > 0) {\r
1394         st->chunk = st->to_read;\r
1395         while ((*datalen) == 0)\r
1396             crReturn(NULL);\r
1397         if (st->chunk > (*datalen))\r
1398             st->chunk = (*datalen);\r
1399         memcpy(st->p, *data, st->chunk);\r
1400         *data += st->chunk;\r
1401         *datalen -= st->chunk;\r
1402         st->p += st->chunk;\r
1403         st->to_read -= st->chunk;\r
1404     }\r
1406     if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data,\r
1407                                      st->biglen, NULL)) {\r
1408         bombout(("Network attack (CRC compensation) detected!"));\r
1409         ssh_free_packet(st->pktin);\r
1410         crStop(NULL);\r
1411     }\r
1413     if (ssh->cipher)\r
1414         ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen);\r
1416     st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4);\r
1417     st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4);\r
1418     if (st->gotcrc != st->realcrc) {\r
1419         bombout(("Incorrect CRC received on packet"));\r
1420         ssh_free_packet(st->pktin);\r
1421         crStop(NULL);\r
1422     }\r
1424     st->pktin->body = st->pktin->data + st->pad + 1;\r
1426     if (ssh->v1_compressing) {\r
1427         unsigned char *decompblk;\r
1428         int decomplen;\r
1429         if (!zlib_decompress_block(ssh->sc_comp_ctx,\r
1430                                    st->pktin->body - 1, st->pktin->length + 1,\r
1431                                    &decompblk, &decomplen)) {\r
1432             bombout(("Zlib decompression encountered invalid data"));\r
1433             ssh_free_packet(st->pktin);\r
1434             crStop(NULL);\r
1435         }\r
1437         if (st->pktin->maxlen < st->pad + decomplen) {\r
1438             st->pktin->maxlen = st->pad + decomplen;\r
1439             st->pktin->data = sresize(st->pktin->data,\r
1440                                       st->pktin->maxlen + APIEXTRA,\r
1441                                       unsigned char);\r
1442             st->pktin->body = st->pktin->data + st->pad + 1;\r
1443         }\r
1445         memcpy(st->pktin->body - 1, decompblk, decomplen);\r
1446         sfree(decompblk);\r
1447         st->pktin->length = decomplen - 1;\r
1448     }\r
1450     st->pktin->type = st->pktin->body[-1];\r
1452     /*\r
1453      * Now pktin->body and pktin->length identify the semantic content\r
1454      * of the packet, excluding the initial type byte.\r
1455      */\r
1457     if (ssh->logctx)\r
1458         ssh1_log_incoming_packet(ssh, st->pktin);\r
1460     st->pktin->savedpos = 0;\r
1462     crFinish(st->pktin);\r
1465 static void ssh2_log_incoming_packet(Ssh ssh, struct Packet *pkt)\r
1467     int nblanks = 0;\r
1468     struct logblank_t blanks[4];\r
1469     char *str;\r
1470     int slen;\r
1472     pkt->savedpos = 0;\r
1474     if (ssh->logomitdata &&\r
1475         (pkt->type == SSH2_MSG_CHANNEL_DATA ||\r
1476          pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {\r
1477         /* "Session data" packets - omit the data string. */\r
1478         ssh_pkt_getuint32(pkt);    /* skip channel id */\r
1479         if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)\r
1480             ssh_pkt_getuint32(pkt);    /* skip extended data type */\r
1481         blanks[nblanks].offset = pkt->savedpos + 4;\r
1482         blanks[nblanks].type = PKTLOG_OMIT;\r
1483         ssh_pkt_getstring(pkt, &str, &slen);\r
1484         if (str) {\r
1485             blanks[nblanks].len = slen;\r
1486             nblanks++;\r
1487         }\r
1488     }\r
1490     log_packet(ssh->logctx, PKT_INCOMING, pkt->type,\r
1491                ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->type),\r
1492                pkt->body, pkt->length, nblanks, blanks, &pkt->sequence,\r
1493                0, NULL);\r
1496 static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt)\r
1498     int nblanks = 0;\r
1499     struct logblank_t blanks[4];\r
1500     char *str;\r
1501     int slen;\r
1503     /*\r
1504      * For outgoing packets, pkt->length represents the length of the\r
1505      * whole packet starting at pkt->data (including some header), and\r
1506      * pkt->body refers to the point within that where the log-worthy\r
1507      * payload begins. However, incoming packets expect pkt->length to\r
1508      * represent only the payload length (that is, it's measured from\r
1509      * pkt->body not from pkt->data). Temporarily adjust our outgoing\r
1510      * packet to conform to the incoming-packet semantics, so that we\r
1511      * can analyse it with the ssh_pkt_get functions.\r
1512      */\r
1513     pkt->length -= (pkt->body - pkt->data);\r
1514     pkt->savedpos = 0;\r
1516     if (ssh->logomitdata &&\r
1517         (pkt->type == SSH2_MSG_CHANNEL_DATA ||\r
1518          pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {\r
1519         /* "Session data" packets - omit the data string. */\r
1520         ssh_pkt_getuint32(pkt);    /* skip channel id */\r
1521         if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)\r
1522             ssh_pkt_getuint32(pkt);    /* skip extended data type */\r
1523         blanks[nblanks].offset = pkt->savedpos + 4;\r
1524         blanks[nblanks].type = PKTLOG_OMIT;\r
1525         ssh_pkt_getstring(pkt, &str, &slen);\r
1526         if (str) {\r
1527             blanks[nblanks].len = slen;\r
1528             nblanks++;\r
1529         }\r
1530     }\r
1532     if (pkt->type == SSH2_MSG_USERAUTH_REQUEST &&\r
1533         conf_get_int(ssh->conf, CONF_logomitpass)) {\r
1534         /* If this is a password packet, blank the password(s). */\r
1535         pkt->savedpos = 0;\r
1536         ssh_pkt_getstring(pkt, &str, &slen);\r
1537         ssh_pkt_getstring(pkt, &str, &slen);\r
1538         ssh_pkt_getstring(pkt, &str, &slen);\r
1539         if (slen == 8 && !memcmp(str, "password", 8)) {\r
1540             ssh2_pkt_getbool(pkt);\r
1541             /* Blank the password field. */\r
1542             blanks[nblanks].offset = pkt->savedpos;\r
1543             blanks[nblanks].type = PKTLOG_BLANK;\r
1544             ssh_pkt_getstring(pkt, &str, &slen);\r
1545             if (str) {\r
1546                 blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;\r
1547                 nblanks++;\r
1548                 /* If there's another password field beyond it (change of\r
1549                  * password), blank that too. */\r
1550                 ssh_pkt_getstring(pkt, &str, &slen);\r
1551                 if (str)\r
1552                     blanks[nblanks-1].len =\r
1553                         pkt->savedpos - blanks[nblanks].offset;\r
1554             }\r
1555         }\r
1556     } else if (ssh->pkt_actx == SSH2_PKTCTX_KBDINTER &&\r
1557                pkt->type == SSH2_MSG_USERAUTH_INFO_RESPONSE &&\r
1558                conf_get_int(ssh->conf, CONF_logomitpass)) {\r
1559         /* If this is a keyboard-interactive response packet, blank\r
1560          * the responses. */\r
1561         pkt->savedpos = 0;\r
1562         ssh_pkt_getuint32(pkt);\r
1563         blanks[nblanks].offset = pkt->savedpos;\r
1564         blanks[nblanks].type = PKTLOG_BLANK;\r
1565         while (1) {\r
1566             ssh_pkt_getstring(pkt, &str, &slen);\r
1567             if (!str)\r
1568                 break;\r
1569         }\r
1570         blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;\r
1571         nblanks++;\r
1572     } else if (pkt->type == SSH2_MSG_CHANNEL_REQUEST &&\r
1573                conf_get_int(ssh->conf, CONF_logomitpass)) {\r
1574         /*\r
1575          * If this is an X forwarding request packet, blank the fake\r
1576          * auth data.\r
1577          *\r
1578          * Note that while we blank the X authentication data here, we\r
1579          * don't take any special action to blank the start of an X11\r
1580          * channel, so using MIT-MAGIC-COOKIE-1 and actually opening\r
1581          * an X connection without having session blanking enabled is\r
1582          * likely to leak your cookie into the log.\r
1583          */\r
1584         pkt->savedpos = 0;\r
1585         ssh_pkt_getuint32(pkt);\r
1586         ssh_pkt_getstring(pkt, &str, &slen);\r
1587         if (slen == 7 && !memcmp(str, "x11-req", 0)) {\r
1588             ssh2_pkt_getbool(pkt);\r
1589             ssh2_pkt_getbool(pkt);\r
1590             ssh_pkt_getstring(pkt, &str, &slen);\r
1591             blanks[nblanks].offset = pkt->savedpos;\r
1592             blanks[nblanks].type = PKTLOG_BLANK;\r
1593             ssh_pkt_getstring(pkt, &str, &slen);\r
1594             if (str) {\r
1595                 blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;\r
1596                 nblanks++;\r
1597             }\r
1598         }\r
1599     }\r
1601     log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],\r
1602                ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),\r
1603                pkt->body, pkt->length, nblanks, blanks,\r
1604                &ssh->v2_outgoing_sequence,\r
1605                pkt->downstream_id, pkt->additional_log_text);\r
1607     /*\r
1608      * Undo the above adjustment of pkt->length, to put the packet\r
1609      * back in the state we found it.\r
1610      */\r
1611     pkt->length += (pkt->body - pkt->data);\r
1614 static struct Packet *ssh2_rdpkt(Ssh ssh, const unsigned char **data,\r
1615                                  int *datalen)\r
1617     struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;\r
1619     crBegin(ssh->ssh2_rdpkt_crstate);\r
1621     st->pktin = ssh_new_packet();\r
1623     st->pktin->type = 0;\r
1624     st->pktin->length = 0;\r
1625     if (ssh->sccipher)\r
1626         st->cipherblk = ssh->sccipher->blksize;\r
1627     else\r
1628         st->cipherblk = 8;\r
1629     if (st->cipherblk < 8)\r
1630         st->cipherblk = 8;\r
1631     st->maclen = ssh->scmac ? ssh->scmac->len : 0;\r
1633     if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&\r
1634         ssh->scmac && !ssh->scmac_etm) {\r
1635         /*\r
1636          * When dealing with a CBC-mode cipher, we want to avoid the\r
1637          * possibility of an attacker's tweaking the ciphertext stream\r
1638          * so as to cause us to feed the same block to the block\r
1639          * cipher more than once and thus leak information\r
1640          * (VU#958563).  The way we do this is not to take any\r
1641          * decisions on the basis of anything we've decrypted until\r
1642          * we've verified it with a MAC.  That includes the packet\r
1643          * length, so we just read data and check the MAC repeatedly,\r
1644          * and when the MAC passes, see if the length we've got is\r
1645          * plausible.\r
1646          *\r
1647          * This defence is unnecessary in OpenSSH ETM mode, because\r
1648          * the whole point of ETM mode is that the attacker can't\r
1649          * tweak the ciphertext stream at all without the MAC\r
1650          * detecting it before we decrypt anything.\r
1651          */\r
1653         /* May as well allocate the whole lot now. */\r
1654         st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,\r
1655                                 unsigned char);\r
1657         /* Read an amount corresponding to the MAC. */\r
1658         for (st->i = 0; st->i < st->maclen; st->i++) {\r
1659             while ((*datalen) == 0)\r
1660                 crReturn(NULL);\r
1661             st->pktin->data[st->i] = *(*data)++;\r
1662             (*datalen)--;\r
1663         }\r
1665         st->packetlen = 0;\r
1666         {\r
1667             unsigned char seq[4];\r
1668             ssh->scmac->start(ssh->sc_mac_ctx);\r
1669             PUT_32BIT(seq, st->incoming_sequence);\r
1670             ssh->scmac->bytes(ssh->sc_mac_ctx, seq, 4);\r
1671         }\r
1673         for (;;) { /* Once around this loop per cipher block. */\r
1674             /* Read another cipher-block's worth, and tack it onto the end. */\r
1675             for (st->i = 0; st->i < st->cipherblk; st->i++) {\r
1676                 while ((*datalen) == 0)\r
1677                     crReturn(NULL);\r
1678                 st->pktin->data[st->packetlen+st->maclen+st->i] = *(*data)++;\r
1679                 (*datalen)--;\r
1680             }\r
1681             /* Decrypt one more block (a little further back in the stream). */\r
1682             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1683                                    st->pktin->data + st->packetlen,\r
1684                                    st->cipherblk);\r
1685             /* Feed that block to the MAC. */\r
1686             ssh->scmac->bytes(ssh->sc_mac_ctx,\r
1687                               st->pktin->data + st->packetlen, st->cipherblk);\r
1688             st->packetlen += st->cipherblk;\r
1689             /* See if that gives us a valid packet. */\r
1690             if (ssh->scmac->verresult(ssh->sc_mac_ctx,\r
1691                                       st->pktin->data + st->packetlen) &&\r
1692                 ((st->len = toint(GET_32BIT(st->pktin->data))) ==\r
1693                  st->packetlen-4))\r
1694                     break;\r
1695             if (st->packetlen >= OUR_V2_PACKETLIMIT) {\r
1696                 bombout(("No valid incoming packet found"));\r
1697                 ssh_free_packet(st->pktin);\r
1698                 crStop(NULL);\r
1699             }       \r
1700         }\r
1701         st->pktin->maxlen = st->packetlen + st->maclen;\r
1702         st->pktin->data = sresize(st->pktin->data,\r
1703                                   st->pktin->maxlen + APIEXTRA,\r
1704                                   unsigned char);\r
1705     } else if (ssh->scmac && ssh->scmac_etm) {\r
1706         st->pktin->data = snewn(4 + APIEXTRA, unsigned char);\r
1708         /*\r
1709          * OpenSSH encrypt-then-MAC mode: the packet length is\r
1710          * unencrypted, unless the cipher supports length encryption.\r
1711          */\r
1712         for (st->i = st->len = 0; st->i < 4; st->i++) {\r
1713             while ((*datalen) == 0)\r
1714                 crReturn(NULL);\r
1715             st->pktin->data[st->i] = *(*data)++;\r
1716             (*datalen)--;\r
1717         }\r
1718         /* Cipher supports length decryption, so do it */\r
1719         if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {\r
1720             /* Keep the packet the same though, so the MAC passes */\r
1721             unsigned char len[4];\r
1722             memcpy(len, st->pktin->data, 4);\r
1723             ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence);\r
1724             st->len = toint(GET_32BIT(len));\r
1725         } else {\r
1726             st->len = toint(GET_32BIT(st->pktin->data));\r
1727         }\r
1729         /*\r
1730          * _Completely_ silly lengths should be stomped on before they\r
1731          * do us any more damage.\r
1732          */\r
1733         if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||\r
1734             st->len % st->cipherblk != 0) {\r
1735             bombout(("Incoming packet length field was garbled"));\r
1736             ssh_free_packet(st->pktin);\r
1737             crStop(NULL);\r
1738         }\r
1740         /*\r
1741          * So now we can work out the total packet length.\r
1742          */\r
1743         st->packetlen = st->len + 4;\r
1745         /*\r
1746          * Allocate memory for the rest of the packet.\r
1747          */\r
1748         st->pktin->maxlen = st->packetlen + st->maclen;\r
1749         st->pktin->data = sresize(st->pktin->data,\r
1750                                   st->pktin->maxlen + APIEXTRA,\r
1751                                   unsigned char);\r
1753         /*\r
1754          * Read the remainder of the packet.\r
1755          */\r
1756         for (st->i = 4; st->i < st->packetlen + st->maclen; st->i++) {\r
1757             while ((*datalen) == 0)\r
1758                 crReturn(NULL);\r
1759             st->pktin->data[st->i] = *(*data)++;\r
1760             (*datalen)--;\r
1761         }\r
1763         /*\r
1764          * Check the MAC.\r
1765          */\r
1766         if (ssh->scmac\r
1767             && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,\r
1768                                    st->len + 4, st->incoming_sequence)) {\r
1769             bombout(("Incorrect MAC received on packet"));\r
1770             ssh_free_packet(st->pktin);\r
1771             crStop(NULL);\r
1772         }\r
1774         /* Decrypt everything between the length field and the MAC. */\r
1775         if (ssh->sccipher)\r
1776             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1777                                    st->pktin->data + 4,\r
1778                                    st->packetlen - 4);\r
1779     } else {\r
1780         st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);\r
1782         /*\r
1783          * Acquire and decrypt the first block of the packet. This will\r
1784          * contain the length and padding details.\r
1785          */\r
1786         for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {\r
1787             while ((*datalen) == 0)\r
1788                 crReturn(NULL);\r
1789             st->pktin->data[st->i] = *(*data)++;\r
1790             (*datalen)--;\r
1791         }\r
1793         if (ssh->sccipher)\r
1794             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1795                                    st->pktin->data, st->cipherblk);\r
1797         /*\r
1798          * Now get the length figure.\r
1799          */\r
1800         st->len = toint(GET_32BIT(st->pktin->data));\r
1802         /*\r
1803          * _Completely_ silly lengths should be stomped on before they\r
1804          * do us any more damage.\r
1805          */\r
1806         if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||\r
1807             (st->len + 4) % st->cipherblk != 0) {\r
1808             bombout(("Incoming packet was garbled on decryption"));\r
1809             ssh_free_packet(st->pktin);\r
1810             crStop(NULL);\r
1811         }\r
1813         /*\r
1814          * So now we can work out the total packet length.\r
1815          */\r
1816         st->packetlen = st->len + 4;\r
1818         /*\r
1819          * Allocate memory for the rest of the packet.\r
1820          */\r
1821         st->pktin->maxlen = st->packetlen + st->maclen;\r
1822         st->pktin->data = sresize(st->pktin->data,\r
1823                                   st->pktin->maxlen + APIEXTRA,\r
1824                                   unsigned char);\r
1826         /*\r
1827          * Read and decrypt the remainder of the packet.\r
1828          */\r
1829         for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;\r
1830              st->i++) {\r
1831             while ((*datalen) == 0)\r
1832                 crReturn(NULL);\r
1833             st->pktin->data[st->i] = *(*data)++;\r
1834             (*datalen)--;\r
1835         }\r
1836         /* Decrypt everything _except_ the MAC. */\r
1837         if (ssh->sccipher)\r
1838             ssh->sccipher->decrypt(ssh->sc_cipher_ctx,\r
1839                                    st->pktin->data + st->cipherblk,\r
1840                                    st->packetlen - st->cipherblk);\r
1842         /*\r
1843          * Check the MAC.\r
1844          */\r
1845         if (ssh->scmac\r
1846             && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,\r
1847                                    st->len + 4, st->incoming_sequence)) {\r
1848             bombout(("Incorrect MAC received on packet"));\r
1849             ssh_free_packet(st->pktin);\r
1850             crStop(NULL);\r
1851         }\r
1852     }\r
1853     /* Get and sanity-check the amount of random padding. */\r
1854     st->pad = st->pktin->data[4];\r
1855     if (st->pad < 4 || st->len - st->pad < 1) {\r
1856         bombout(("Invalid padding length on received packet"));\r
1857         ssh_free_packet(st->pktin);\r
1858         crStop(NULL);\r
1859     }\r
1860     /*\r
1861      * This enables us to deduce the payload length.\r
1862      */\r
1863     st->payload = st->len - st->pad - 1;\r
1865     st->pktin->length = st->payload + 5;\r
1866     st->pktin->encrypted_len = st->packetlen;\r
1868     st->pktin->sequence = st->incoming_sequence++;\r
1870     st->pktin->length = st->packetlen - st->pad;\r
1871     assert(st->pktin->length >= 0);\r
1873     /*\r
1874      * Decompress packet payload.\r
1875      */\r
1876     {\r
1877         unsigned char *newpayload;\r
1878         int newlen;\r
1879         if (ssh->sccomp &&\r
1880             ssh->sccomp->decompress(ssh->sc_comp_ctx,\r
1881                                     st->pktin->data + 5, st->pktin->length - 5,\r
1882                                     &newpayload, &newlen)) {\r
1883             if (st->pktin->maxlen < newlen + 5) {\r
1884                 st->pktin->maxlen = newlen + 5;\r
1885                 st->pktin->data = sresize(st->pktin->data,\r
1886                                           st->pktin->maxlen + APIEXTRA,\r
1887                                           unsigned char);\r
1888             }\r
1889             st->pktin->length = 5 + newlen;\r
1890             memcpy(st->pktin->data + 5, newpayload, newlen);\r
1891             sfree(newpayload);\r
1892         }\r
1893     }\r
1895     /*\r
1896      * RFC 4253 doesn't explicitly say that completely empty packets\r
1897      * with no type byte are forbidden, so treat them as deserving\r
1898      * an SSH_MSG_UNIMPLEMENTED.\r
1899      */\r
1900     if (st->pktin->length <= 5) { /* == 5 we hope, but robustness */\r
1901         ssh2_msg_something_unimplemented(ssh, st->pktin);\r
1902         crStop(NULL);\r
1903     }\r
1904     /*\r
1905      * pktin->body and pktin->length should identify the semantic\r
1906      * content of the packet, excluding the initial type byte.\r
1907      */\r
1908     st->pktin->type = st->pktin->data[5];\r
1909     st->pktin->body = st->pktin->data + 6;\r
1910     st->pktin->length -= 6;\r
1911     assert(st->pktin->length >= 0);    /* one last double-check */\r
1913     if (ssh->logctx)\r
1914         ssh2_log_incoming_packet(ssh, st->pktin);\r
1916     st->pktin->savedpos = 0;\r
1918     crFinish(st->pktin);\r
1921 static struct Packet *ssh2_bare_connection_rdpkt(Ssh ssh,\r
1922                                                  const unsigned char **data,\r
1923                                                  int *datalen)\r
1925     struct rdpkt2_bare_state_tag *st = &ssh->rdpkt2_bare_state;\r
1927     crBegin(ssh->ssh2_bare_rdpkt_crstate);\r
1929     /*\r
1930      * Read the packet length field.\r
1931      */\r
1932     for (st->i = 0; st->i < 4; st->i++) {\r
1933         while ((*datalen) == 0)\r
1934             crReturn(NULL);\r
1935         st->length[st->i] = *(*data)++;\r
1936         (*datalen)--;\r
1937     }\r
1939     st->packetlen = toint(GET_32BIT_MSB_FIRST(st->length));\r
1940     if (st->packetlen <= 0 || st->packetlen >= OUR_V2_PACKETLIMIT) {\r
1941         bombout(("Invalid packet length received"));\r
1942         crStop(NULL);\r
1943     }\r
1945     st->pktin = ssh_new_packet();\r
1946     st->pktin->data = snewn(st->packetlen, unsigned char);\r
1948     st->pktin->encrypted_len = st->packetlen;\r
1950     st->pktin->sequence = st->incoming_sequence++;\r
1952     /*\r
1953      * Read the remainder of the packet.\r
1954      */\r
1955     for (st->i = 0; st->i < st->packetlen; st->i++) {\r
1956         while ((*datalen) == 0)\r
1957             crReturn(NULL);\r
1958         st->pktin->data[st->i] = *(*data)++;\r
1959         (*datalen)--;\r
1960     }\r
1962     /*\r
1963      * pktin->body and pktin->length should identify the semantic\r
1964      * content of the packet, excluding the initial type byte.\r
1965      */\r
1966     st->pktin->type = st->pktin->data[0];\r
1967     st->pktin->body = st->pktin->data + 1;\r
1968     st->pktin->length = st->packetlen - 1;\r
1970     /*\r
1971      * Log incoming packet, possibly omitting sensitive fields.\r
1972      */\r
1973     if (ssh->logctx)\r
1974         ssh2_log_incoming_packet(ssh, st->pktin);\r
1976     st->pktin->savedpos = 0;\r
1978     crFinish(st->pktin);\r
1981 static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p)\r
1983     int pad, biglen, i, pktoffs;\r
1984     unsigned long crc;\r
1985 #ifdef __SC__\r
1986     /*\r
1987      * XXX various versions of SC (including 8.8.4) screw up the\r
1988      * register allocation in this function and use the same register\r
1989      * (D6) for len and as a temporary, with predictable results.  The\r
1990      * following sledgehammer prevents this.\r
1991      */\r
1992     volatile\r
1993 #endif\r
1994     int len;\r
1996     if (ssh->logctx)\r
1997         ssh1_log_outgoing_packet(ssh, pkt);\r
1999     if (ssh->v1_compressing) {\r
2000         unsigned char *compblk;\r
2001         int complen;\r
2002         zlib_compress_block(ssh->cs_comp_ctx,\r
2003                             pkt->data + 12, pkt->length - 12,\r
2004                             &compblk, &complen);\r
2005         ssh_pkt_ensure(pkt, complen + 2);   /* just in case it's got bigger */\r
2006         memcpy(pkt->data + 12, compblk, complen);\r
2007         sfree(compblk);\r
2008         pkt->length = complen + 12;\r
2009     }\r
2011     ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */\r
2012     pkt->length += 4;\r
2013     len = pkt->length - 4 - 8;  /* len(type+data+CRC) */\r
2014     pad = 8 - (len % 8);\r
2015     pktoffs = 8 - pad;\r
2016     biglen = len + pad;         /* len(padding+type+data+CRC) */\r
2018     for (i = pktoffs; i < 4+8; i++)\r
2019         pkt->data[i] = random_byte();\r
2020     crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */\r
2021     PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);\r
2022     PUT_32BIT(pkt->data + pktoffs, len);\r
2024     if (ssh->cipher)\r
2025         ssh->cipher->encrypt(ssh->v1_cipher_ctx,\r
2026                              pkt->data + pktoffs + 4, biglen);\r
2028     if (offset_p) *offset_p = pktoffs;\r
2029     return biglen + 4;          /* len(length+padding+type+data+CRC) */\r
2032 static int s_write(Ssh ssh, void *data, int len)\r
2034     if (ssh->logctx)\r
2035         log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len,\r
2036                    0, NULL, NULL, 0, NULL);\r
2037     if (!ssh->s)\r
2038         return 0;\r
2039     return sk_write(ssh->s, (char *)data, len);\r
2042 static void s_wrpkt(Ssh ssh, struct Packet *pkt)\r
2044     int len, backlog, offset;\r
2045     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
2046     backlog = s_write(ssh, pkt->data + offset, len);\r
2047     if (backlog > SSH_MAX_BACKLOG)\r
2048         ssh_throttle_all(ssh, 1, backlog);\r
2049     ssh_free_packet(pkt);\r
2052 static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt)\r
2054     int len, offset;\r
2055     len = s_wrpkt_prepare(ssh, pkt, &offset);\r
2056     if (ssh->deferred_len + len > ssh->deferred_size) {\r
2057         ssh->deferred_size = ssh->deferred_len + len + 128;\r
2058         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
2059                                           ssh->deferred_size,\r
2060                                           unsigned char);\r
2061     }\r
2062     memcpy(ssh->deferred_send_data + ssh->deferred_len,\r
2063            pkt->data + offset, len);\r
2064     ssh->deferred_len += len;\r
2065     ssh_free_packet(pkt);\r
2068 /*\r
2069  * Construct a SSH-1 packet with the specified contents.\r
2070  * (This all-at-once interface used to be the only one, but now SSH-1\r
2071  * packets can also be constructed incrementally.)\r
2072  */\r
2073 static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap)\r
2075     int argtype;\r
2076     Bignum bn;\r
2077     struct Packet *pkt;\r
2079     pkt = ssh1_pkt_init(pkttype);\r
2081     while ((argtype = va_arg(ap, int)) != PKT_END) {\r
2082         unsigned char *argp, argchar;\r
2083         char *sargp;\r
2084         unsigned long argint;\r
2085         int arglen;\r
2086         switch (argtype) {\r
2087           /* Actual fields in the packet */\r
2088           case PKT_INT:\r
2089             argint = va_arg(ap, int);\r
2090             ssh_pkt_adduint32(pkt, argint);\r
2091             break;\r
2092           case PKT_CHAR:\r
2093             argchar = (unsigned char) va_arg(ap, int);\r
2094             ssh_pkt_addbyte(pkt, argchar);\r
2095             break;\r
2096           case PKT_DATA:\r
2097             argp = va_arg(ap, unsigned char *);\r
2098             arglen = va_arg(ap, int);\r
2099             ssh_pkt_adddata(pkt, argp, arglen);\r
2100             break;\r
2101           case PKT_STR:\r
2102             sargp = va_arg(ap, char *);\r
2103             ssh_pkt_addstring(pkt, sargp);\r
2104             break;\r
2105           case PKT_BIGNUM:\r
2106             bn = va_arg(ap, Bignum);\r
2107             ssh1_pkt_addmp(pkt, bn);\r
2108             break;\r
2109         }\r
2110     }\r
2112     return pkt;\r
2115 static void send_packet(Ssh ssh, int pkttype, ...)\r
2117     struct Packet *pkt;\r
2118     va_list ap;\r
2119     va_start(ap, pkttype);\r
2120     pkt = construct_packet(ssh, pkttype, ap);\r
2121     va_end(ap);\r
2122     s_wrpkt(ssh, pkt);\r
2125 static void defer_packet(Ssh ssh, int pkttype, ...)\r
2127     struct Packet *pkt;\r
2128     va_list ap;\r
2129     va_start(ap, pkttype);\r
2130     pkt = construct_packet(ssh, pkttype, ap);\r
2131     va_end(ap);\r
2132     s_wrpkt_defer(ssh, pkt);\r
2135 static int ssh_versioncmp(const char *a, const char *b)\r
2137     char *ae, *be;\r
2138     unsigned long av, bv;\r
2140     av = strtoul(a, &ae, 10);\r
2141     bv = strtoul(b, &be, 10);\r
2142     if (av != bv)\r
2143         return (av < bv ? -1 : +1);\r
2144     if (*ae == '.')\r
2145         ae++;\r
2146     if (*be == '.')\r
2147         be++;\r
2148     av = strtoul(ae, &ae, 10);\r
2149     bv = strtoul(be, &be, 10);\r
2150     if (av != bv)\r
2151         return (av < bv ? -1 : +1);\r
2152     return 0;\r
2155 /*\r
2156  * Utility routines for putting an SSH-protocol `string' and\r
2157  * `uint32' into a hash state.\r
2158  */\r
2159 static void hash_string(const struct ssh_hash *h, void *s, void *str, int len)\r
2161     unsigned char lenblk[4];\r
2162     PUT_32BIT(lenblk, len);\r
2163     h->bytes(s, lenblk, 4);\r
2164     h->bytes(s, str, len);\r
2167 static void hash_uint32(const struct ssh_hash *h, void *s, unsigned i)\r
2169     unsigned char intblk[4];\r
2170     PUT_32BIT(intblk, i);\r
2171     h->bytes(s, intblk, 4);\r
2174 /*\r
2175  * Packet construction functions. Mostly shared between SSH-1 and SSH-2.\r
2176  */\r
2177 static void ssh_pkt_ensure(struct Packet *pkt, int length)\r
2179     if (pkt->maxlen < length) {\r
2180         unsigned char *body = pkt->body;\r
2181         int offset = body ? body - pkt->data : 0;\r
2182         pkt->maxlen = length + 256;\r
2183         pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char);\r
2184         if (body) pkt->body = pkt->data + offset;\r
2185     }\r
2187 static void ssh_pkt_adddata(struct Packet *pkt, const void *data, int len)\r
2189     pkt->length += len;\r
2190     ssh_pkt_ensure(pkt, pkt->length);\r
2191     memcpy(pkt->data + pkt->length - len, data, len);\r
2193 static void ssh_pkt_addbyte(struct Packet *pkt, unsigned char byte)\r
2195     ssh_pkt_adddata(pkt, &byte, 1);\r
2197 static void ssh2_pkt_addbool(struct Packet *pkt, unsigned char value)\r
2199     ssh_pkt_adddata(pkt, &value, 1);\r
2201 static void ssh_pkt_adduint32(struct Packet *pkt, unsigned long value)\r
2203     unsigned char x[4];\r
2204     PUT_32BIT(x, value);\r
2205     ssh_pkt_adddata(pkt, x, 4);\r
2207 static void ssh_pkt_addstring_start(struct Packet *pkt)\r
2209     ssh_pkt_adduint32(pkt, 0);\r
2210     pkt->savedpos = pkt->length;\r
2212 static void ssh_pkt_addstring_data(struct Packet *pkt, const char *data,\r
2213                                    int len)\r
2215     ssh_pkt_adddata(pkt, data, len);\r
2216     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);\r
2218 static void ssh_pkt_addstring_str(struct Packet *pkt, const char *data)\r
2220   ssh_pkt_addstring_data(pkt, data, strlen(data));\r
2222 static void ssh_pkt_addstring(struct Packet *pkt, const char *data)\r
2224     ssh_pkt_addstring_start(pkt);\r
2225     ssh_pkt_addstring_str(pkt, data);\r
2227 static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b)\r
2229     int len = ssh1_bignum_length(b);\r
2230     unsigned char *data = snewn(len, unsigned char);\r
2231     (void) ssh1_write_bignum(data, b);\r
2232     ssh_pkt_adddata(pkt, data, len);\r
2233     sfree(data);\r
2235 static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)\r
2237     unsigned char *p;\r
2238     int i, n = (bignum_bitcount(b) + 7) / 8;\r
2239     p = snewn(n + 1, unsigned char);\r
2240     p[0] = 0;\r
2241     for (i = 1; i <= n; i++)\r
2242         p[i] = bignum_byte(b, n - i);\r
2243     i = 0;\r
2244     while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)\r
2245         i++;\r
2246     memmove(p, p + i, n + 1 - i);\r
2247     *len = n + 1 - i;\r
2248     return p;\r
2250 static void ssh2_pkt_addmp(struct Packet *pkt, Bignum b)\r
2252     unsigned char *p;\r
2253     int len;\r
2254     p = ssh2_mpint_fmt(b, &len);\r
2255     ssh_pkt_addstring_start(pkt);\r
2256     ssh_pkt_addstring_data(pkt, (char *)p, len);\r
2257     sfree(p);\r
2260 static struct Packet *ssh1_pkt_init(int pkt_type)\r
2262     struct Packet *pkt = ssh_new_packet();\r
2263     pkt->length = 4 + 8;            /* space for length + max padding */\r
2264     ssh_pkt_addbyte(pkt, pkt_type);\r
2265     pkt->body = pkt->data + pkt->length;\r
2266     pkt->type = pkt_type;\r
2267     pkt->downstream_id = 0;\r
2268     pkt->additional_log_text = NULL;\r
2269     return pkt;\r
2272 /* For legacy code (SSH-1 and -2 packet construction used to be separate) */\r
2273 #define ssh2_pkt_ensure(pkt, length) ssh_pkt_ensure(pkt, length)\r
2274 #define ssh2_pkt_adddata(pkt, data, len) ssh_pkt_adddata(pkt, data, len)\r
2275 #define ssh2_pkt_addbyte(pkt, byte) ssh_pkt_addbyte(pkt, byte)\r
2276 #define ssh2_pkt_adduint32(pkt, value) ssh_pkt_adduint32(pkt, value)\r
2277 #define ssh2_pkt_addstring_start(pkt) ssh_pkt_addstring_start(pkt)\r
2278 #define ssh2_pkt_addstring_str(pkt, data) ssh_pkt_addstring_str(pkt, data)\r
2279 #define ssh2_pkt_addstring_data(pkt, data, len) ssh_pkt_addstring_data(pkt, data, len)\r
2280 #define ssh2_pkt_addstring(pkt, data) ssh_pkt_addstring(pkt, data)\r
2282 static struct Packet *ssh2_pkt_init(int pkt_type)\r
2284     struct Packet *pkt = ssh_new_packet();\r
2285     pkt->length = 5; /* space for packet length + padding length */\r
2286     pkt->forcepad = 0;\r
2287     pkt->type = pkt_type;\r
2288     ssh_pkt_addbyte(pkt, (unsigned char) pkt_type);\r
2289     pkt->body = pkt->data + pkt->length; /* after packet type */\r
2290     pkt->downstream_id = 0;\r
2291     pkt->additional_log_text = NULL;\r
2292     return pkt;\r
2295 /*\r
2296  * Construct an SSH-2 final-form packet: compress it, encrypt it,\r
2297  * put the MAC on it. Final packet, ready to be sent, is stored in\r
2298  * pkt->data. Total length is returned.\r
2299  */\r
2300 static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt)\r
2302     int cipherblk, maclen, padding, unencrypted_prefix, i;\r
2304     if (ssh->logctx)\r
2305         ssh2_log_outgoing_packet(ssh, pkt);\r
2307     if (ssh->bare_connection) {\r
2308         /*\r
2309          * Trivial packet construction for the bare connection\r
2310          * protocol.\r
2311          */\r
2312         PUT_32BIT(pkt->data + 1, pkt->length - 5);\r
2313         pkt->body = pkt->data + 1;\r
2314         ssh->v2_outgoing_sequence++;   /* only for diagnostics, really */\r
2315         return pkt->length - 1;\r
2316     }\r
2318     /*\r
2319      * Compress packet payload.\r
2320      */\r
2321     {\r
2322         unsigned char *newpayload;\r
2323         int newlen;\r
2324         if (ssh->cscomp &&\r
2325             ssh->cscomp->compress(ssh->cs_comp_ctx, pkt->data + 5,\r
2326                                   pkt->length - 5,\r
2327                                   &newpayload, &newlen)) {\r
2328             pkt->length = 5;\r
2329             ssh2_pkt_adddata(pkt, newpayload, newlen);\r
2330             sfree(newpayload);\r
2331         }\r
2332     }\r
2334     /*\r
2335      * Add padding. At least four bytes, and must also bring total\r
2336      * length (minus MAC) up to a multiple of the block size.\r
2337      * If pkt->forcepad is set, make sure the packet is at least that size\r
2338      * after padding.\r
2339      */\r
2340     cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8;  /* block size */\r
2341     cipherblk = cipherblk < 8 ? 8 : cipherblk;  /* or 8 if blksize < 8 */\r
2342     padding = 4;\r
2343     unencrypted_prefix = (ssh->csmac && ssh->csmac_etm) ? 4 : 0;\r
2344     if (pkt->length + padding < pkt->forcepad)\r
2345         padding = pkt->forcepad - pkt->length;\r
2346     padding +=\r
2347         (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk)\r
2348         % cipherblk;\r
2349     assert(padding <= 255);\r
2350     maclen = ssh->csmac ? ssh->csmac->len : 0;\r
2351     ssh2_pkt_ensure(pkt, pkt->length + padding + maclen);\r
2352     pkt->data[4] = padding;\r
2353     for (i = 0; i < padding; i++)\r
2354         pkt->data[pkt->length + i] = random_byte();\r
2355     PUT_32BIT(pkt->data, pkt->length + padding - 4);\r
2357     /* Encrypt length if the scheme requires it */\r
2358     if (ssh->cscipher && (ssh->cscipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {\r
2359         ssh->cscipher->encrypt_length(ssh->cs_cipher_ctx, pkt->data, 4,\r
2360                                       ssh->v2_outgoing_sequence);\r
2361     }\r
2363     if (ssh->csmac && ssh->csmac_etm) {\r
2364         /*\r
2365          * OpenSSH-defined encrypt-then-MAC protocol.\r
2366          */\r
2367         if (ssh->cscipher)\r
2368             ssh->cscipher->encrypt(ssh->cs_cipher_ctx,\r
2369                                    pkt->data + 4, pkt->length + padding - 4);\r
2370         ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,\r
2371                              pkt->length + padding,\r
2372                              ssh->v2_outgoing_sequence);\r
2373     } else {\r
2374         /*\r
2375          * SSH-2 standard protocol.\r
2376          */\r
2377         if (ssh->csmac)\r
2378             ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,\r
2379                                  pkt->length + padding,\r
2380                                  ssh->v2_outgoing_sequence);\r
2381         if (ssh->cscipher)\r
2382             ssh->cscipher->encrypt(ssh->cs_cipher_ctx,\r
2383                                    pkt->data, pkt->length + padding);\r
2384     }\r
2386     ssh->v2_outgoing_sequence++;       /* whether or not we MACed */\r
2387     pkt->encrypted_len = pkt->length + padding;\r
2389     /* Ready-to-send packet starts at pkt->data. We return length. */\r
2390     pkt->body = pkt->data;\r
2391     return pkt->length + padding + maclen;\r
2394 /*\r
2395  * Routines called from the main SSH code to send packets. There\r
2396  * are quite a few of these, because we have two separate\r
2397  * mechanisms for delaying the sending of packets:\r
2398  * \r
2399  *  - In order to send an IGNORE message and a password message in\r
2400  *    a single fixed-length blob, we require the ability to\r
2401  *    concatenate the encrypted forms of those two packets _into_ a\r
2402  *    single blob and then pass it to our <network.h> transport\r
2403  *    layer in one go. Hence, there's a deferment mechanism which\r
2404  *    works after packet encryption.\r
2405  * \r
2406  *  - In order to avoid sending any connection-layer messages\r
2407  *    during repeat key exchange, we have to queue up any such\r
2408  *    outgoing messages _before_ they are encrypted (and in\r
2409  *    particular before they're allocated sequence numbers), and\r
2410  *    then send them once we've finished.\r
2411  * \r
2412  * I call these mechanisms `defer' and `queue' respectively, so as\r
2413  * to distinguish them reasonably easily.\r
2414  * \r
2415  * The functions send_noqueue() and defer_noqueue() free the packet\r
2416  * structure they are passed. Every outgoing packet goes through\r
2417  * precisely one of these functions in its life; packets passed to\r
2418  * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of\r
2419  * these or get queued, and then when the queue is later emptied\r
2420  * the packets are all passed to defer_noqueue().\r
2421  *\r
2422  * When using a CBC-mode cipher, it's necessary to ensure that an\r
2423  * attacker can't provide data to be encrypted using an IV that they\r
2424  * know.  We ensure this by prefixing each packet that might contain\r
2425  * user data with an SSH_MSG_IGNORE.  This is done using the deferral\r
2426  * mechanism, so in this case send_noqueue() ends up redirecting to\r
2427  * defer_noqueue().  If you don't like this inefficiency, don't use\r
2428  * CBC.\r
2429  */\r
2431 static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int);\r
2432 static void ssh_pkt_defersend(Ssh);\r
2434 /*\r
2435  * Send an SSH-2 packet immediately, without queuing or deferring.\r
2436  */\r
2437 static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt)\r
2439     int len;\r
2440     int backlog;\r
2441     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) {\r
2442         /* We need to send two packets, so use the deferral mechanism. */\r
2443         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2444         ssh_pkt_defersend(ssh);\r
2445         return;\r
2446     }\r
2447     len = ssh2_pkt_construct(ssh, pkt);\r
2448     backlog = s_write(ssh, pkt->body, len);\r
2449     if (backlog > SSH_MAX_BACKLOG)\r
2450         ssh_throttle_all(ssh, 1, backlog);\r
2452     ssh->outgoing_data_size += pkt->encrypted_len;\r
2453     if (!ssh->kex_in_progress &&\r
2454         !ssh->bare_connection &&\r
2455         ssh->max_data_size != 0 &&\r
2456         ssh->outgoing_data_size > ssh->max_data_size)\r
2457         do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2459     ssh_free_packet(pkt);\r
2462 /*\r
2463  * Defer an SSH-2 packet.\r
2464  */\r
2465 static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore)\r
2467     int len;\r
2468     if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) &&\r
2469         ssh->deferred_len == 0 && !noignore &&\r
2470         !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2471         /*\r
2472          * Interpose an SSH_MSG_IGNORE to ensure that user data don't\r
2473          * get encrypted with a known IV.\r
2474          */\r
2475         struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2476         ssh2_pkt_addstring_start(ipkt);\r
2477         ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE);\r
2478     }\r
2479     len = ssh2_pkt_construct(ssh, pkt);\r
2480     if (ssh->deferred_len + len > ssh->deferred_size) {\r
2481         ssh->deferred_size = ssh->deferred_len + len + 128;\r
2482         ssh->deferred_send_data = sresize(ssh->deferred_send_data,\r
2483                                           ssh->deferred_size,\r
2484                                           unsigned char);\r
2485     }\r
2486     memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->body, len);\r
2487     ssh->deferred_len += len;\r
2488     ssh->deferred_data_size += pkt->encrypted_len;\r
2489     ssh_free_packet(pkt);\r
2492 /*\r
2493  * Queue an SSH-2 packet.\r
2494  */\r
2495 static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt)\r
2497     assert(ssh->queueing);\r
2499     if (ssh->queuelen >= ssh->queuesize) {\r
2500         ssh->queuesize = ssh->queuelen + 32;\r
2501         ssh->queue = sresize(ssh->queue, ssh->queuesize, struct Packet *);\r
2502     }\r
2504     ssh->queue[ssh->queuelen++] = pkt;\r
2507 /*\r
2508  * Either queue or send a packet, depending on whether queueing is\r
2509  * set.\r
2510  */\r
2511 static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt)\r
2513     if (ssh->queueing)\r
2514         ssh2_pkt_queue(ssh, pkt);\r
2515     else\r
2516         ssh2_pkt_send_noqueue(ssh, pkt);\r
2519 /*\r
2520  * Either queue or defer a packet, depending on whether queueing is\r
2521  * set.\r
2522  */\r
2523 static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt)\r
2525     if (ssh->queueing)\r
2526         ssh2_pkt_queue(ssh, pkt);\r
2527     else\r
2528         ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);\r
2531 /*\r
2532  * Send the whole deferred data block constructed by\r
2533  * ssh2_pkt_defer() or SSH-1's defer_packet().\r
2534  * \r
2535  * The expected use of the defer mechanism is that you call\r
2536  * ssh2_pkt_defer() a few times, then call ssh_pkt_defersend(). If\r
2537  * not currently queueing, this simply sets up deferred_send_data\r
2538  * and then sends it. If we _are_ currently queueing, the calls to\r
2539  * ssh2_pkt_defer() put the deferred packets on to the queue\r
2540  * instead, and therefore ssh_pkt_defersend() has no deferred data\r
2541  * to send. Hence, there's no need to make it conditional on\r
2542  * ssh->queueing.\r
2543  */\r
2544 static void ssh_pkt_defersend(Ssh ssh)\r
2546     int backlog;\r
2547     backlog = s_write(ssh, ssh->deferred_send_data, ssh->deferred_len);\r
2548     ssh->deferred_len = ssh->deferred_size = 0;\r
2549     sfree(ssh->deferred_send_data);\r
2550     ssh->deferred_send_data = NULL;\r
2551     if (backlog > SSH_MAX_BACKLOG)\r
2552         ssh_throttle_all(ssh, 1, backlog);\r
2554     if (ssh->version == 2) {\r
2555         ssh->outgoing_data_size += ssh->deferred_data_size;\r
2556         ssh->deferred_data_size = 0;\r
2557         if (!ssh->kex_in_progress &&\r
2558             !ssh->bare_connection &&\r
2559             ssh->max_data_size != 0 &&\r
2560             ssh->outgoing_data_size > ssh->max_data_size)\r
2561             do_ssh2_transport(ssh, "too much data sent", -1, NULL);\r
2562     }\r
2565 /*\r
2566  * Send a packet whose length needs to be disguised (typically\r
2567  * passwords or keyboard-interactive responses).\r
2568  */\r
2569 static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt,\r
2570                                        int padsize)\r
2572 #if 0\r
2573     if (0) {\r
2574         /*\r
2575          * The simplest way to do this is to adjust the\r
2576          * variable-length padding field in the outgoing packet.\r
2577          * \r
2578          * Currently compiled out, because some Cisco SSH servers\r
2579          * don't like excessively padded packets (bah, why's it\r
2580          * always Cisco?)\r
2581          */\r
2582         pkt->forcepad = padsize;\r
2583         ssh2_pkt_send(ssh, pkt);\r
2584     } else\r
2585 #endif\r
2586     {\r
2587         /*\r
2588          * If we can't do that, however, an alternative approach is\r
2589          * to use the pkt_defer mechanism to bundle the packet\r
2590          * tightly together with an SSH_MSG_IGNORE such that their\r
2591          * combined length is a constant. So first we construct the\r
2592          * final form of this packet and defer its sending.\r
2593          */\r
2594         ssh2_pkt_defer(ssh, pkt);\r
2596         /*\r
2597          * Now construct an SSH_MSG_IGNORE which includes a string\r
2598          * that's an exact multiple of the cipher block size. (If\r
2599          * the cipher is NULL so that the block size is\r
2600          * unavailable, we don't do this trick at all, because we\r
2601          * gain nothing by it.)\r
2602          */\r
2603         if (ssh->cscipher &&\r
2604             !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
2605             int stringlen, i;\r
2607             stringlen = (256 - ssh->deferred_len);\r
2608             stringlen += ssh->cscipher->blksize - 1;\r
2609             stringlen -= (stringlen % ssh->cscipher->blksize);\r
2610             if (ssh->cscomp) {\r
2611                 /*\r
2612                  * Temporarily disable actual compression, so we\r
2613                  * can guarantee to get this string exactly the\r
2614                  * length we want it. The compression-disabling\r
2615                  * routine should return an integer indicating how\r
2616                  * many bytes we should adjust our string length\r
2617                  * by.\r
2618                  */\r
2619                 stringlen -=\r
2620                     ssh->cscomp->disable_compression(ssh->cs_comp_ctx);\r
2621             }\r
2622             pkt = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
2623             ssh2_pkt_addstring_start(pkt);\r
2624             for (i = 0; i < stringlen; i++) {\r
2625                 char c = (char) random_byte();\r
2626                 ssh2_pkt_addstring_data(pkt, &c, 1);\r
2627             }\r
2628             ssh2_pkt_defer(ssh, pkt);\r
2629         }\r
2630         ssh_pkt_defersend(ssh);\r
2631     }\r
2634 /*\r
2635  * Send all queued SSH-2 packets. We send them by means of\r
2636  * ssh2_pkt_defer_noqueue(), in case they included a pair of\r
2637  * packets that needed to be lumped together.\r
2638  */\r
2639 static void ssh2_pkt_queuesend(Ssh ssh)\r
2641     int i;\r
2643     assert(!ssh->queueing);\r
2645     for (i = 0; i < ssh->queuelen; i++)\r
2646         ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE);\r
2647     ssh->queuelen = 0;\r
2649     ssh_pkt_defersend(ssh);\r
2652 #if 0\r
2653 void bndebug(char *string, Bignum b)\r
2655     unsigned char *p;\r
2656     int i, len;\r
2657     p = ssh2_mpint_fmt(b, &len);\r
2658     debug(("%s", string));\r
2659     for (i = 0; i < len; i++)\r
2660         debug((" %02x", p[i]));\r
2661     debug(("\n"));\r
2662     sfree(p);\r
2664 #endif\r
2666 static void hash_mpint(const struct ssh_hash *h, void *s, Bignum b)\r
2668     unsigned char *p;\r
2669     int len;\r
2670     p = ssh2_mpint_fmt(b, &len);\r
2671     hash_string(h, s, p, len);\r
2672     sfree(p);\r
2675 /*\r
2676  * Packet decode functions for both SSH-1 and SSH-2.\r
2677  */\r
2678 static unsigned long ssh_pkt_getuint32(struct Packet *pkt)\r
2680     unsigned long value;\r
2681     if (pkt->length - pkt->savedpos < 4)\r
2682         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2683     value = GET_32BIT(pkt->body + pkt->savedpos);\r
2684     pkt->savedpos += 4;\r
2685     return value;\r
2687 static int ssh2_pkt_getbool(struct Packet *pkt)\r
2689     unsigned long value;\r
2690     if (pkt->length - pkt->savedpos < 1)\r
2691         return 0;                      /* arrgh, no way to decline (FIXME?) */\r
2692     value = pkt->body[pkt->savedpos] != 0;\r
2693     pkt->savedpos++;\r
2694     return value;\r
2696 static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length)\r
2698     int len;\r
2699     *p = NULL;\r
2700     *length = 0;\r
2701     if (pkt->length - pkt->savedpos < 4)\r
2702         return;\r
2703     len = toint(GET_32BIT(pkt->body + pkt->savedpos));\r
2704     if (len < 0)\r
2705         return;\r
2706     *length = len;\r
2707     pkt->savedpos += 4;\r
2708     if (pkt->length - pkt->savedpos < *length)\r
2709         return;\r
2710     *p = (char *)(pkt->body + pkt->savedpos);\r
2711     pkt->savedpos += *length;\r
2713 static void *ssh_pkt_getdata(struct Packet *pkt, int length)\r
2715     if (pkt->length - pkt->savedpos < length)\r
2716         return NULL;\r
2717     pkt->savedpos += length;\r
2718     return pkt->body + (pkt->savedpos - length);\r
2720 static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key,\r
2721                               const unsigned char **keystr)\r
2723     int j;\r
2725     j = makekey(pkt->body + pkt->savedpos,\r
2726                 pkt->length - pkt->savedpos,\r
2727                 key, keystr, 0);\r
2729     if (j < 0)\r
2730         return FALSE;\r
2731     \r
2732     pkt->savedpos += j;\r
2733     assert(pkt->savedpos < pkt->length);\r
2735     return TRUE;\r
2737 static Bignum ssh1_pkt_getmp(struct Packet *pkt)\r
2739     int j;\r
2740     Bignum b;\r
2742     j = ssh1_read_bignum(pkt->body + pkt->savedpos,\r
2743                          pkt->length - pkt->savedpos, &b);\r
2745     if (j < 0)\r
2746         return NULL;\r
2748     pkt->savedpos += j;\r
2749     return b;\r
2751 static Bignum ssh2_pkt_getmp(struct Packet *pkt)\r
2753     char *p;\r
2754     int length;\r
2755     Bignum b;\r
2757     ssh_pkt_getstring(pkt, &p, &length);\r
2758     if (!p)\r
2759         return NULL;\r
2760     if (p[0] & 0x80)\r
2761         return NULL;\r
2762     b = bignum_from_bytes((unsigned char *)p, length);\r
2763     return b;\r
2766 /*\r
2767  * Helper function to add an SSH-2 signature blob to a packet.\r
2768  * Expects to be shown the public key blob as well as the signature\r
2769  * blob. Normally works just like ssh2_pkt_addstring, but will\r
2770  * fiddle with the signature packet if necessary for\r
2771  * BUG_SSH2_RSA_PADDING.\r
2772  */\r
2773 static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt,\r
2774                              void *pkblob_v, int pkblob_len,\r
2775                              void *sigblob_v, int sigblob_len)\r
2777     unsigned char *pkblob = (unsigned char *)pkblob_v;\r
2778     unsigned char *sigblob = (unsigned char *)sigblob_v;\r
2780     /* dmemdump(pkblob, pkblob_len); */\r
2781     /* dmemdump(sigblob, sigblob_len); */\r
2783     /*\r
2784      * See if this is in fact an ssh-rsa signature and a buggy\r
2785      * server; otherwise we can just do this the easy way.\r
2786      */\r
2787     if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && pkblob_len > 4+7+4 &&\r
2788         (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {\r
2789         int pos, len, siglen;\r
2791         /*\r
2792          * Find the byte length of the modulus.\r
2793          */\r
2795         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2796         len = toint(GET_32BIT(pkblob+pos)); /* get length of exponent */\r
2797         if (len < 0 || len > pkblob_len - pos - 4)\r
2798             goto give_up;\r
2799         pos += 4 + len;                /* skip over exponent */\r
2800         if (pkblob_len - pos < 4)\r
2801             goto give_up;\r
2802         len = toint(GET_32BIT(pkblob+pos)); /* find length of modulus */\r
2803         if (len < 0 || len > pkblob_len - pos - 4)\r
2804             goto give_up;\r
2805         pos += 4;                      /* find modulus itself */\r
2806         while (len > 0 && pkblob[pos] == 0)\r
2807             len--, pos++;\r
2808         /* debug(("modulus length is %d\n", len)); */\r
2810         /*\r
2811          * Now find the signature integer.\r
2812          */\r
2813         pos = 4+7;                     /* skip over "ssh-rsa" */\r
2814         if (sigblob_len < pos+4)\r
2815             goto give_up;\r
2816         siglen = toint(GET_32BIT(sigblob+pos));\r
2817         if (siglen != sigblob_len - pos - 4)\r
2818             goto give_up;\r
2819         /* debug(("signature length is %d\n", siglen)); */\r
2821         if (len != siglen) {\r
2822             unsigned char newlen[4];\r
2823             ssh2_pkt_addstring_start(pkt);\r
2824             ssh2_pkt_addstring_data(pkt, (char *)sigblob, pos);\r
2825             /* dmemdump(sigblob, pos); */\r
2826             pos += 4;                  /* point to start of actual sig */\r
2827             PUT_32BIT(newlen, len);\r
2828             ssh2_pkt_addstring_data(pkt, (char *)newlen, 4);\r
2829             /* dmemdump(newlen, 4); */\r
2830             newlen[0] = 0;\r
2831             while (len-- > siglen) {\r
2832                 ssh2_pkt_addstring_data(pkt, (char *)newlen, 1);\r
2833                 /* dmemdump(newlen, 1); */\r
2834             }\r
2835             ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen);\r
2836             /* dmemdump(sigblob+pos, siglen); */\r
2837             return;\r
2838         }\r
2840         /* Otherwise fall through and do it the easy way. We also come\r
2841          * here as a fallback if we discover above that the key blob\r
2842          * is misformatted in some way. */\r
2843       give_up:;\r
2844     }\r
2846     ssh2_pkt_addstring_start(pkt);\r
2847     ssh2_pkt_addstring_data(pkt, (char *)sigblob, sigblob_len);\r
2850 /*\r
2851  * Examine the remote side's version string and compare it against\r
2852  * a list of known buggy implementations.\r
2853  */\r
2854 static void ssh_detect_bugs(Ssh ssh, char *vstring)\r
2856     char *imp;                         /* pointer to implementation part */\r
2857     imp = vstring;\r
2858     imp += strcspn(imp, "-");\r
2859     if (*imp) imp++;\r
2860     imp += strcspn(imp, "-");\r
2861     if (*imp) imp++;\r
2863     ssh->remote_bugs = 0;\r
2865     /*\r
2866      * General notes on server version strings:\r
2867      *  - Not all servers reporting "Cisco-1.25" have all the bugs listed\r
2868      *    here -- in particular, we've heard of one that's perfectly happy\r
2869      *    with SSH1_MSG_IGNOREs -- but this string never seems to change,\r
2870      *    so we can't distinguish them.\r
2871      */\r
2872     if (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == FORCE_ON ||\r
2873         (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == AUTO &&\r
2874          (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||\r
2875           !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||\r
2876           !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||\r
2877           !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {\r
2878         /*\r
2879          * These versions don't support SSH1_MSG_IGNORE, so we have\r
2880          * to use a different defence against password length\r
2881          * sniffing.\r
2882          */\r
2883         ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;\r
2884         logevent("We believe remote version has SSH-1 ignore bug");\r
2885     }\r
2887     if (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == FORCE_ON ||\r
2888         (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == AUTO &&\r
2889          (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) {\r
2890         /*\r
2891          * These versions need a plain password sent; they can't\r
2892          * handle having a null and a random length of data after\r
2893          * the password.\r
2894          */\r
2895         ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;\r
2896         logevent("We believe remote version needs a plain SSH-1 password");\r
2897     }\r
2899     if (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == FORCE_ON ||\r
2900         (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == AUTO &&\r
2901          (!strcmp(imp, "Cisco-1.25")))) {\r
2902         /*\r
2903          * These versions apparently have no clue whatever about\r
2904          * RSA authentication and will panic and die if they see\r
2905          * an AUTH_RSA message.\r
2906          */\r
2907         ssh->remote_bugs |= BUG_CHOKES_ON_RSA;\r
2908         logevent("We believe remote version can't handle SSH-1 RSA authentication");\r
2909     }\r
2911     if (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == FORCE_ON ||\r
2912         (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == AUTO &&\r
2913          !wc_match("* VShell", imp) &&\r
2914          (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) ||\r
2915           wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) ||\r
2916           wc_match("2.1 *", imp)))) {\r
2917         /*\r
2918          * These versions have the HMAC bug.\r
2919          */\r
2920         ssh->remote_bugs |= BUG_SSH2_HMAC;\r
2921         logevent("We believe remote version has SSH-2 HMAC bug");\r
2922     }\r
2924     if (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == FORCE_ON ||\r
2925         (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == AUTO &&\r
2926          !wc_match("* VShell", imp) &&\r
2927          (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) {\r
2928         /*\r
2929          * These versions have the key-derivation bug (failing to\r
2930          * include the literal shared secret in the hashes that\r
2931          * generate the keys).\r
2932          */\r
2933         ssh->remote_bugs |= BUG_SSH2_DERIVEKEY;\r
2934         logevent("We believe remote version has SSH-2 key-derivation bug");\r
2935     }\r
2937     if (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == FORCE_ON ||\r
2938         (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == AUTO &&\r
2939          (wc_match("OpenSSH_2.[5-9]*", imp) ||\r
2940           wc_match("OpenSSH_3.[0-2]*", imp) ||\r
2941           wc_match("mod_sftp/0.[0-8]*", imp) ||\r
2942           wc_match("mod_sftp/0.9.[0-8]", imp)))) {\r
2943         /*\r
2944          * These versions have the SSH-2 RSA padding bug.\r
2945          */\r
2946         ssh->remote_bugs |= BUG_SSH2_RSA_PADDING;\r
2947         logevent("We believe remote version has SSH-2 RSA padding bug");\r
2948     }\r
2950     if (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == FORCE_ON ||\r
2951         (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == AUTO &&\r
2952          wc_match("OpenSSH_2.[0-2]*", imp))) {\r
2953         /*\r
2954          * These versions have the SSH-2 session-ID bug in\r
2955          * public-key authentication.\r
2956          */\r
2957         ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID;\r
2958         logevent("We believe remote version has SSH-2 public-key-session-ID bug");\r
2959     }\r
2961     if (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == FORCE_ON ||\r
2962         (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == AUTO &&\r
2963          (wc_match("DigiSSH_2.0", imp) ||\r
2964           wc_match("OpenSSH_2.[0-4]*", imp) ||\r
2965           wc_match("OpenSSH_2.5.[0-3]*", imp) ||\r
2966           wc_match("Sun_SSH_1.0", imp) ||\r
2967           wc_match("Sun_SSH_1.0.1", imp) ||\r
2968           /* All versions <= 1.2.6 (they changed their format in 1.2.7) */\r
2969           wc_match("WeOnlyDo-*", imp)))) {\r
2970         /*\r
2971          * These versions have the SSH-2 rekey bug.\r
2972          */\r
2973         ssh->remote_bugs |= BUG_SSH2_REKEY;\r
2974         logevent("We believe remote version has SSH-2 rekey bug");\r
2975     }\r
2977     if (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == FORCE_ON ||\r
2978         (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == AUTO &&\r
2979          (wc_match("1.36_sshlib GlobalSCAPE", imp) ||\r
2980           wc_match("1.36 sshlib: GlobalScape", imp)))) {\r
2981         /*\r
2982          * This version ignores our makpkt and needs to be throttled.\r
2983          */\r
2984         ssh->remote_bugs |= BUG_SSH2_MAXPKT;\r
2985         logevent("We believe remote version ignores SSH-2 maximum packet size");\r
2986     }\r
2988     if (conf_get_int(ssh->conf, CONF_sshbug_ignore2) == FORCE_ON) {\r
2989         /*\r
2990          * Servers that don't support SSH2_MSG_IGNORE. Currently,\r
2991          * none detected automatically.\r
2992          */\r
2993         ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;\r
2994         logevent("We believe remote version has SSH-2 ignore bug");\r
2995     }\r
2997     if (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == FORCE_ON ||\r
2998         (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == AUTO &&\r
2999          (wc_match("OpenSSH_2.[235]*", imp)))) {\r
3000         /*\r
3001          * These versions only support the original (pre-RFC4419)\r
3002          * SSH-2 GEX request, and disconnect with a protocol error if\r
3003          * we use the newer version.\r
3004          */\r
3005         ssh->remote_bugs |= BUG_SSH2_OLDGEX;\r
3006         logevent("We believe remote version has outdated SSH-2 GEX");\r
3007     }\r
3009     if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) {\r
3010         /*\r
3011          * Servers that don't support our winadj request for one\r
3012          * reason or another. Currently, none detected automatically.\r
3013          */\r
3014         ssh->remote_bugs |= BUG_CHOKES_ON_WINADJ;\r
3015         logevent("We believe remote version has winadj bug");\r
3016     }\r
3018     if (conf_get_int(ssh->conf, CONF_sshbug_chanreq) == FORCE_ON ||\r
3019         (conf_get_int(ssh->conf, CONF_sshbug_chanreq) == AUTO &&\r
3020          (wc_match("OpenSSH_[2-5].*", imp) ||\r
3021           wc_match("OpenSSH_6.[0-6]*", imp) ||\r
3022           wc_match("dropbear_0.[2-4][0-9]*", imp) ||\r
3023           wc_match("dropbear_0.5[01]*", imp)))) {\r
3024         /*\r
3025          * These versions have the SSH-2 channel request bug.\r
3026          * OpenSSH 6.7 and above do not:\r
3027          * https://bugzilla.mindrot.org/show_bug.cgi?id=1818\r
3028          * dropbear_0.52 and above do not:\r
3029          * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c\r
3030          */\r
3031         ssh->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY;\r
3032         logevent("We believe remote version has SSH-2 channel request bug");\r
3033     }\r
3036 /*\r
3037  * The `software version' part of an SSH version string is required\r
3038  * to contain no spaces or minus signs.\r
3039  */\r
3040 static void ssh_fix_verstring(char *str)\r
3042     /* Eat "<protoversion>-". */\r
3043     while (*str && *str != '-') str++;\r
3044     assert(*str == '-'); str++;\r
3046     /* Convert minus signs and spaces in the remaining string into\r
3047      * underscores. */\r
3048     while (*str) {\r
3049         if (*str == '-' || *str == ' ')\r
3050             *str = '_';\r
3051         str++;\r
3052     }\r
3055 /*\r
3056  * Send an appropriate SSH version string.\r
3057  */\r
3058 static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers)\r
3060     char *verstring;\r
3062     if (ssh->version == 2) {\r
3063         /*\r
3064          * Construct a v2 version string.\r
3065          */\r
3066         verstring = dupprintf("%s2.0-%s\015\012", protoname, sshver);\r
3067     } else {\r
3068         /*\r
3069          * Construct a v1 version string.\r
3070          */\r
3071         assert(!strcmp(protoname, "SSH-")); /* no v1 bare connection protocol */\r
3072         verstring = dupprintf("SSH-%s-%s\012",\r
3073                               (ssh_versioncmp(svers, "1.5") <= 0 ?\r
3074                                svers : "1.5"),\r
3075                               sshver);\r
3076     }\r
3078     ssh_fix_verstring(verstring + strlen(protoname));\r
3079 #ifdef FUZZING\r
3080     /* FUZZING make PuTTY insecure, so make live use difficult. */\r
3081     verstring[0] = 'I';\r
3082 #endif\r
3084     if (ssh->version == 2) {\r
3085         size_t len;\r
3086         /*\r
3087          * Record our version string.\r
3088          */\r
3089         len = strcspn(verstring, "\015\012");\r
3090         ssh->v_c = snewn(len + 1, char);\r
3091         memcpy(ssh->v_c, verstring, len);\r
3092         ssh->v_c[len] = 0;\r
3093     }\r
3095     logeventf(ssh, "We claim version: %.*s",\r
3096               strcspn(verstring, "\015\012"), verstring);\r
3097     s_write(ssh, verstring, strlen(verstring));\r
3098     sfree(verstring);\r
3101 static int do_ssh_init(Ssh ssh, unsigned char c)\r
3103     static const char protoname[] = "SSH-";\r
3105     struct do_ssh_init_state {\r
3106         int crLine;\r
3107         int vslen;\r
3108         char version[10];\r
3109         char *vstring;\r
3110         int vstrsize;\r
3111         int i;\r
3112         int proto1, proto2;\r
3113     };\r
3114     crState(do_ssh_init_state);\r
3115     \r
3116     crBeginState;\r
3118     /* Search for a line beginning with the protocol name prefix in\r
3119      * the input. */\r
3120     for (;;) {\r
3121         for (s->i = 0; protoname[s->i]; s->i++) {\r
3122             if ((char)c != protoname[s->i]) goto no;\r
3123             crReturn(1);\r
3124         }\r
3125         break;\r
3126       no:\r
3127         while (c != '\012')\r
3128             crReturn(1);\r
3129         crReturn(1);\r
3130     }\r
3132     ssh->session_started = TRUE;\r
3134     s->vstrsize = sizeof(protoname) + 16;\r
3135     s->vstring = snewn(s->vstrsize, char);\r
3136     strcpy(s->vstring, protoname);\r
3137     s->vslen = strlen(protoname);\r
3138     s->i = 0;\r
3139     while (1) {\r
3140         if (s->vslen >= s->vstrsize - 1) {\r
3141             s->vstrsize += 16;\r
3142             s->vstring = sresize(s->vstring, s->vstrsize, char);\r
3143         }\r
3144         s->vstring[s->vslen++] = c;\r
3145         if (s->i >= 0) {\r
3146             if (c == '-') {\r
3147                 s->version[s->i] = '\0';\r
3148                 s->i = -1;\r
3149             } else if (s->i < sizeof(s->version) - 1)\r
3150                 s->version[s->i++] = c;\r
3151         } else if (c == '\012')\r
3152             break;\r
3153         crReturn(1);                   /* get another char */\r
3154     }\r
3156     ssh->agentfwd_enabled = FALSE;\r
3157     ssh->rdpkt2_state.incoming_sequence = 0;\r
3159     s->vstring[s->vslen] = 0;\r
3160     s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */\r
3161     logeventf(ssh, "Server version: %s", s->vstring);\r
3162     ssh_detect_bugs(ssh, s->vstring);\r
3164     /*\r
3165      * Decide which SSH protocol version to support.\r
3166      */\r
3168     /* Anything strictly below "2.0" means protocol 1 is supported. */\r
3169     s->proto1 = ssh_versioncmp(s->version, "2.0") < 0;\r
3170     /* Anything greater or equal to "1.99" means protocol 2 is supported. */\r
3171     s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;\r
3173     if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {\r
3174         if (!s->proto1) {\r
3175             bombout(("SSH protocol version 1 required by our configuration "\r
3176                      "but not provided by server"));\r
3177             crStop(0);\r
3178         }\r
3179     } else if (conf_get_int(ssh->conf, CONF_sshprot) == 3) {\r
3180         if (!s->proto2) {\r
3181             bombout(("SSH protocol version 2 required by our configuration "\r
3182                      "but server only provides (old, insecure) SSH-1"));\r
3183             crStop(0);\r
3184         }\r
3185     } else {\r
3186         /* No longer support values 1 or 2 for CONF_sshprot */\r
3187         assert(!"Unexpected value for CONF_sshprot");\r
3188     }\r
3190     if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1))\r
3191         ssh->version = 2;\r
3192     else\r
3193         ssh->version = 1;\r
3195     logeventf(ssh, "Using SSH protocol version %d", ssh->version);\r
3197     /* Send the version string, if we haven't already */\r
3198     if (conf_get_int(ssh->conf, CONF_sshprot) != 3)\r
3199         ssh_send_verstring(ssh, protoname, s->version);\r
3201     if (ssh->version == 2) {\r
3202         size_t len;\r
3203         /*\r
3204          * Record their version string.\r
3205          */\r
3206         len = strcspn(s->vstring, "\015\012");\r
3207         ssh->v_s = snewn(len + 1, char);\r
3208         memcpy(ssh->v_s, s->vstring, len);\r
3209         ssh->v_s[len] = 0;\r
3210             \r
3211         /*\r
3212          * Initialise SSH-2 protocol.\r
3213          */\r
3214         ssh->protocol = ssh2_protocol;\r
3215         ssh2_protocol_setup(ssh);\r
3216         ssh->s_rdpkt = ssh2_rdpkt;\r
3217     } else {\r
3218         /*\r
3219          * Initialise SSH-1 protocol.\r
3220          */\r
3221         ssh->protocol = ssh1_protocol;\r
3222         ssh1_protocol_setup(ssh);\r
3223         ssh->s_rdpkt = ssh1_rdpkt;\r
3224     }\r
3225     if (ssh->version == 2)\r
3226         do_ssh2_transport(ssh, NULL, -1, NULL);\r
3228     update_specials_menu(ssh->frontend);\r
3229     ssh->state = SSH_STATE_BEFORE_SIZE;\r
3230     ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh);\r
3232     sfree(s->vstring);\r
3234     crFinish(0);\r
3237 static int do_ssh_connection_init(Ssh ssh, unsigned char c)\r
3239     /*\r
3240      * Ordinary SSH begins with the banner "SSH-x.y-...". This is just\r
3241      * the ssh-connection part, extracted and given a trivial binary\r
3242      * packet protocol, so we replace 'SSH-' at the start with a new\r
3243      * name. In proper SSH style (though of course this part of the\r
3244      * proper SSH protocol _isn't_ subject to this kind of\r
3245      * DNS-domain-based extension), we define the new name in our\r
3246      * extension space.\r
3247      */\r
3248     static const char protoname[] =\r
3249         "SSHCONNECTION@putty.projects.tartarus.org-";\r
3251     struct do_ssh_connection_init_state {\r
3252         int crLine;\r
3253         int vslen;\r
3254         char version[10];\r
3255         char *vstring;\r
3256         int vstrsize;\r
3257         int i;\r
3258     };\r
3259     crState(do_ssh_connection_init_state);\r
3260     \r
3261     crBeginState;\r
3263     /* Search for a line beginning with the protocol name prefix in\r
3264      * the input. */\r
3265     for (;;) {\r
3266         for (s->i = 0; protoname[s->i]; s->i++) {\r
3267             if ((char)c != protoname[s->i]) goto no;\r
3268             crReturn(1);\r
3269         }\r
3270         break;\r
3271       no:\r
3272         while (c != '\012')\r
3273             crReturn(1);\r
3274         crReturn(1);\r
3275     }\r
3277     s->vstrsize = sizeof(protoname) + 16;\r
3278     s->vstring = snewn(s->vstrsize, char);\r
3279     strcpy(s->vstring, protoname);\r
3280     s->vslen = strlen(protoname);\r
3281     s->i = 0;\r
3282     while (1) {\r
3283         if (s->vslen >= s->vstrsize - 1) {\r
3284             s->vstrsize += 16;\r
3285             s->vstring = sresize(s->vstring, s->vstrsize, char);\r
3286         }\r
3287         s->vstring[s->vslen++] = c;\r
3288         if (s->i >= 0) {\r
3289             if (c == '-') {\r
3290                 s->version[s->i] = '\0';\r
3291                 s->i = -1;\r
3292             } else if (s->i < sizeof(s->version) - 1)\r
3293                 s->version[s->i++] = c;\r
3294         } else if (c == '\012')\r
3295             break;\r
3296         crReturn(1);                   /* get another char */\r
3297     }\r
3299     ssh->agentfwd_enabled = FALSE;\r
3300     ssh->rdpkt2_bare_state.incoming_sequence = 0;\r
3302     s->vstring[s->vslen] = 0;\r
3303     s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */\r
3304     logeventf(ssh, "Server version: %s", s->vstring);\r
3305     ssh_detect_bugs(ssh, s->vstring);\r
3307     /*\r
3308      * Decide which SSH protocol version to support. This is easy in\r
3309      * bare ssh-connection mode: only 2.0 is legal.\r
3310      */\r
3311     if (ssh_versioncmp(s->version, "2.0") < 0) {\r
3312         bombout(("Server announces compatibility with SSH-1 in bare ssh-connection protocol"));\r
3313         crStop(0);\r
3314     }\r
3315     if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {\r
3316         bombout(("Bare ssh-connection protocol cannot be run in SSH-1-only mode"));\r
3317         crStop(0);\r
3318     }\r
3320     ssh->version = 2;\r
3322     logeventf(ssh, "Using bare ssh-connection protocol");\r
3324     /* Send the version string, if we haven't already */\r
3325     ssh_send_verstring(ssh, protoname, s->version);\r
3327     /*\r
3328      * Initialise bare connection protocol.\r
3329      */\r
3330     ssh->protocol = ssh2_bare_connection_protocol;\r
3331     ssh2_bare_connection_protocol_setup(ssh);\r
3332     ssh->s_rdpkt = ssh2_bare_connection_rdpkt;\r
3334     update_specials_menu(ssh->frontend);\r
3335     ssh->state = SSH_STATE_BEFORE_SIZE;\r
3336     ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh);\r
3338     /*\r
3339      * Get authconn (really just conn) under way.\r
3340      */\r
3341     do_ssh2_authconn(ssh, NULL, 0, NULL);\r
3343     sfree(s->vstring);\r
3345     crFinish(0);\r
3348 static void ssh_process_incoming_data(Ssh ssh,\r
3349                                       const unsigned char **data, int *datalen)\r
3351     struct Packet *pktin;\r
3353     pktin = ssh->s_rdpkt(ssh, data, datalen);\r
3354     if (pktin) {\r
3355         ssh->protocol(ssh, NULL, 0, pktin);\r
3356         ssh_free_packet(pktin);\r
3357     }\r
3360 static void ssh_queue_incoming_data(Ssh ssh,\r
3361                                     const unsigned char **data, int *datalen)\r
3363     bufchain_add(&ssh->queued_incoming_data, *data, *datalen);\r
3364     *data += *datalen;\r
3365     *datalen = 0;\r
3368 static void ssh_process_queued_incoming_data(Ssh ssh)\r
3370     void *vdata;\r
3371     const unsigned char *data;\r
3372     int len, origlen;\r
3374     while (!ssh->frozen && bufchain_size(&ssh->queued_incoming_data)) {\r
3375         bufchain_prefix(&ssh->queued_incoming_data, &vdata, &len);\r
3376         data = vdata;\r
3377         origlen = len;\r
3379         while (!ssh->frozen && len > 0)\r
3380             ssh_process_incoming_data(ssh, &data, &len);\r
3382         if (origlen > len)\r
3383             bufchain_consume(&ssh->queued_incoming_data, origlen - len);\r
3384     }\r
3387 static void ssh_set_frozen(Ssh ssh, int frozen)\r
3389     if (ssh->s)\r
3390         sk_set_frozen(ssh->s, frozen);\r
3391     ssh->frozen = frozen;\r
3394 static void ssh_gotdata(Ssh ssh, const unsigned char *data, int datalen)\r
3396     /* Log raw data, if we're in that mode. */\r
3397     if (ssh->logctx)\r
3398         log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,\r
3399                    0, NULL, NULL, 0, NULL);\r
3401     crBegin(ssh->ssh_gotdata_crstate);\r
3403     /*\r
3404      * To begin with, feed the characters one by one to the\r
3405      * protocol initialisation / selection function do_ssh_init().\r
3406      * When that returns 0, we're done with the initial greeting\r
3407      * exchange and can move on to packet discipline.\r
3408      */\r
3409     while (1) {\r
3410         int ret;                       /* need not be kept across crReturn */\r
3411         if (datalen == 0)\r
3412             crReturnV;                 /* more data please */\r
3413         ret = ssh->do_ssh_init(ssh, *data);\r
3414         data++;\r
3415         datalen--;\r
3416         if (ret == 0)\r
3417             break;\r
3418     }\r
3420     /*\r
3421      * We emerge from that loop when the initial negotiation is\r
3422      * over and we have selected an s_rdpkt function. Now pass\r
3423      * everything to s_rdpkt, and then pass the resulting packets\r
3424      * to the proper protocol handler.\r
3425      */\r
3427     while (1) {\r
3428         while (bufchain_size(&ssh->queued_incoming_data) > 0 || datalen > 0) {\r
3429             if (ssh->frozen) {\r
3430                 ssh_queue_incoming_data(ssh, &data, &datalen);\r
3431                 /* This uses up all data and cannot cause anything interesting\r
3432                  * to happen; indeed, for anything to happen at all, we must\r
3433                  * return, so break out. */\r
3434                 break;\r
3435             } else if (bufchain_size(&ssh->queued_incoming_data) > 0) {\r
3436                 /* This uses up some or all data, and may freeze the\r
3437                  * session. */\r
3438                 ssh_process_queued_incoming_data(ssh);\r
3439             } else {\r
3440                 /* This uses up some or all data, and may freeze the\r
3441                  * session. */\r
3442                 ssh_process_incoming_data(ssh, &data, &datalen);\r
3443             }\r
3444             /* FIXME this is probably EBW. */\r
3445             if (ssh->state == SSH_STATE_CLOSED)\r
3446                 return;\r
3447         }\r
3448         /* We're out of data. Go and get some more. */\r
3449         crReturnV;\r
3450     }\r
3451     crFinishV;\r
3454 static int ssh_do_close(Ssh ssh, int notify_exit)\r
3456     int ret = 0;\r
3457     struct ssh_channel *c;\r
3459     ssh->state = SSH_STATE_CLOSED;\r
3460     expire_timer_context(ssh);\r
3461     if (ssh->s) {\r
3462         sk_close(ssh->s);\r
3463         ssh->s = NULL;\r
3464         if (notify_exit)\r
3465             notify_remote_exit(ssh->frontend);\r
3466         else\r
3467             ret = 1;\r
3468     }\r
3469     /*\r
3470      * Now we must shut down any port- and X-forwarded channels going\r
3471      * through this connection.\r
3472      */\r
3473     if (ssh->channels) {\r
3474         while (NULL != (c = index234(ssh->channels, 0))) {\r
3475             ssh_channel_close_local(c, NULL);\r
3476             del234(ssh->channels, c); /* moving next one to index 0 */\r
3477             if (ssh->version == 2)\r
3478                 bufchain_clear(&c->v.v2.outbuffer);\r
3479             sfree(c);\r
3480         }\r
3481     }\r
3482     /*\r
3483      * Go through port-forwardings, and close any associated\r
3484      * listening sockets.\r
3485      */\r
3486     if (ssh->portfwds) {\r
3487         struct ssh_portfwd *pf;\r
3488         while (NULL != (pf = index234(ssh->portfwds, 0))) {\r
3489             /* Dispose of any listening socket. */\r
3490             if (pf->local)\r
3491                 pfl_terminate(pf->local);\r
3492             del234(ssh->portfwds, pf); /* moving next one to index 0 */\r
3493             free_portfwd(pf);\r
3494         }\r
3495         freetree234(ssh->portfwds);\r
3496         ssh->portfwds = NULL;\r
3497     }\r
3499     /*\r
3500      * Also stop attempting to connection-share.\r
3501      */\r
3502     if (ssh->connshare) {\r
3503         sharestate_free(ssh->connshare);\r
3504         ssh->connshare = NULL;\r
3505     }\r
3507     return ret;\r
3510 static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port,\r
3511                            const char *error_msg, int error_code)\r
3513     Ssh ssh = (Ssh) plug;\r
3515     /*\r
3516      * While we're attempting connection sharing, don't loudly log\r
3517      * everything that happens. Real TCP connections need to be logged\r
3518      * when we _start_ trying to connect, because it might be ages\r
3519      * before they respond if something goes wrong; but connection\r
3520      * sharing is local and quick to respond, and it's sufficient to\r
3521      * simply wait and see whether it worked afterwards.\r
3522      */\r
3524     if (!ssh->attempting_connshare)\r
3525         backend_socket_log(ssh->frontend, type, addr, port,\r
3526                            error_msg, error_code, ssh->conf,\r
3527                            ssh->session_started);\r
3530 void ssh_connshare_log(Ssh ssh, int event, const char *logtext,\r
3531                        const char *ds_err, const char *us_err)\r
3533     if (event == SHARE_NONE) {\r
3534         /* In this case, 'logtext' is an error message indicating a\r
3535          * reason why connection sharing couldn't be set up _at all_.\r
3536          * Failing that, ds_err and us_err indicate why we couldn't be\r
3537          * a downstream and an upstream respectively. */\r
3538         if (logtext) {\r
3539             logeventf(ssh, "Could not set up connection sharing: %s", logtext);\r
3540         } else {\r
3541             if (ds_err)\r
3542                 logeventf(ssh, "Could not set up connection sharing"\r
3543                           " as downstream: %s", ds_err);\r
3544             if (us_err)\r
3545                 logeventf(ssh, "Could not set up connection sharing"\r
3546                           " as upstream: %s", us_err);\r
3547         }\r
3548     } else if (event == SHARE_DOWNSTREAM) {\r
3549         /* In this case, 'logtext' is a local endpoint address */\r
3550         logeventf(ssh, "Using existing shared connection at %s", logtext);\r
3551         /* Also we should mention this in the console window to avoid\r
3552          * confusing users as to why this window doesn't behave the\r
3553          * usual way. */\r
3554         if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {\r
3555             c_write_str(ssh,"Reusing a shared connection to this server.\r\n");\r
3556         }\r
3557     } else if (event == SHARE_UPSTREAM) {\r
3558         /* In this case, 'logtext' is a local endpoint address too */\r
3559         logeventf(ssh, "Sharing this connection at %s", logtext);\r
3560     }\r
3563 static void ssh_closing(Plug plug, const char *error_msg, int error_code,\r
3564                         int calling_back)\r
3566     Ssh ssh = (Ssh) plug;\r
3567     int need_notify = ssh_do_close(ssh, FALSE);\r
3569     if (!error_msg) {\r
3570         if (!ssh->close_expected)\r
3571             error_msg = "Server unexpectedly closed network connection";\r
3572         else\r
3573             error_msg = "Server closed network connection";\r
3574     }\r
3576     if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0)\r
3577         ssh->exitcode = 0;\r
3579     if (need_notify)\r
3580         notify_remote_exit(ssh->frontend);\r
3582     if (error_msg)\r
3583         logevent(error_msg);\r
3584     if (!ssh->close_expected || !ssh->clean_exit)\r
3585         connection_fatal(ssh->frontend, "%s", error_msg);\r
3588 static void ssh_receive(Plug plug, int urgent, char *data, int len)\r
3590     Ssh ssh = (Ssh) plug;\r
3591     ssh_gotdata(ssh, (unsigned char *)data, len);\r
3592     if (ssh->state == SSH_STATE_CLOSED) {\r
3593         ssh_do_close(ssh, TRUE);\r
3594     }\r
3597 static void ssh_sent(Plug plug, int bufsize)\r
3599     Ssh ssh = (Ssh) plug;\r
3600     /*\r
3601      * If the send backlog on the SSH socket itself clears, we\r
3602      * should unthrottle the whole world if it was throttled.\r
3603      */\r
3604     if (bufsize < SSH_MAX_BACKLOG)\r
3605         ssh_throttle_all(ssh, 0, bufsize);\r
3608 static void ssh_hostport_setup(const char *host, int port, Conf *conf,\r
3609                                char **savedhost, int *savedport,\r
3610                                char **loghost_ret)\r
3612     char *loghost = conf_get_str(conf, CONF_loghost);\r
3613     if (loghost_ret)\r
3614         *loghost_ret = loghost;\r
3616     if (*loghost) {\r
3617         char *tmphost;\r
3618         char *colon;\r
3620         tmphost = dupstr(loghost);\r
3621         *savedport = 22;               /* default ssh port */\r
3623         /*\r
3624          * A colon suffix on the hostname string also lets us affect\r
3625          * savedport. (Unless there are multiple colons, in which case\r
3626          * we assume this is an unbracketed IPv6 literal.)\r
3627          */\r
3628         colon = host_strrchr(tmphost, ':');\r
3629         if (colon && colon == host_strchr(tmphost, ':')) {\r
3630             *colon++ = '\0';\r
3631             if (*colon)\r
3632                 *savedport = atoi(colon);\r
3633         }\r
3635         *savedhost = host_strduptrim(tmphost);\r
3636         sfree(tmphost);\r
3637     } else {\r
3638         *savedhost = host_strduptrim(host);\r
3639         if (port < 0)\r
3640             port = 22;                 /* default ssh port */\r
3641         *savedport = port;\r
3642     }\r
3645 static int ssh_test_for_upstream(const char *host, int port, Conf *conf)\r
3647     char *savedhost;\r
3648     int savedport;\r
3649     int ret;\r
3651     random_ref(); /* platform may need this to determine share socket name */\r
3652     ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL);\r
3653     ret = ssh_share_test_for_upstream(savedhost, savedport, conf);\r
3654     sfree(savedhost);\r
3655     random_unref();\r
3657     return ret;\r
3660 /*\r
3661  * Connect to specified host and port.\r
3662  * Returns an error message, or NULL on success.\r
3663  * Also places the canonical host name into `realhost'. It must be\r
3664  * freed by the caller.\r
3665  */\r
3666 static const char *connect_to_host(Ssh ssh, const char *host, int port,\r
3667                                    char **realhost, int nodelay, int keepalive)\r
3669     static const struct plug_function_table fn_table = {\r
3670         ssh_socket_log,\r
3671         ssh_closing,\r
3672         ssh_receive,\r
3673         ssh_sent,\r
3674         NULL\r
3675     };\r
3677     SockAddr addr;\r
3678     const char *err;\r
3679     char *loghost;\r
3680     int addressfamily, sshprot;\r
3682     ssh_hostport_setup(host, port, ssh->conf,\r
3683                        &ssh->savedhost, &ssh->savedport, &loghost);\r
3685     ssh->fn = &fn_table;               /* make 'ssh' usable as a Plug */\r
3687     /*\r
3688      * Try connection-sharing, in case that means we don't open a\r
3689      * socket after all. ssh_connection_sharing_init will connect to a\r
3690      * previously established upstream if it can, and failing that,\r
3691      * establish a listening socket for _us_ to be the upstream. In\r
3692      * the latter case it will return NULL just as if it had done\r
3693      * nothing, because here we only need to care if we're a\r
3694      * downstream and need to do our connection setup differently.\r
3695      */\r
3696     ssh->connshare = NULL;\r
3697     ssh->attempting_connshare = TRUE;  /* affects socket logging behaviour */\r
3698     ssh->s = ssh_connection_sharing_init(ssh->savedhost, ssh->savedport,\r
3699                                          ssh->conf, ssh, &ssh->connshare);\r
3700     ssh->attempting_connshare = FALSE;\r
3701     if (ssh->s != NULL) {\r
3702         /*\r
3703          * We are a downstream.\r
3704          */\r
3705         ssh->bare_connection = TRUE;\r
3706         ssh->do_ssh_init = do_ssh_connection_init;\r
3707         ssh->fullhostname = NULL;\r
3708         *realhost = dupstr(host);      /* best we can do */\r
3709     } else {\r
3710         /*\r
3711          * We're not a downstream, so open a normal socket.\r
3712          */\r
3713         ssh->do_ssh_init = do_ssh_init;\r
3715         /*\r
3716          * Try to find host.\r
3717          */\r
3718         addressfamily = conf_get_int(ssh->conf, CONF_addressfamily);\r
3719         addr = name_lookup(host, port, realhost, ssh->conf, addressfamily,\r
3720                            ssh->frontend, "SSH connection");\r
3721         if ((err = sk_addr_error(addr)) != NULL) {\r
3722             sk_addr_free(addr);\r
3723             return err;\r
3724         }\r
3725         ssh->fullhostname = dupstr(*realhost);   /* save in case of GSSAPI */\r
3727         ssh->s = new_connection(addr, *realhost, port,\r
3728                                 0, 1, nodelay, keepalive,\r
3729                                 (Plug) ssh, ssh->conf);\r
3730         if ((err = sk_socket_error(ssh->s)) != NULL) {\r
3731             ssh->s = NULL;\r
3732             notify_remote_exit(ssh->frontend);\r
3733             return err;\r
3734         }\r
3735     }\r
3737     /*\r
3738      * The SSH version number is always fixed (since we no longer support\r
3739      * fallback between versions), so set it now, and if it's SSH-2,\r
3740      * send the version string now too.\r
3741      */\r
3742     sshprot = conf_get_int(ssh->conf, CONF_sshprot);\r
3743     assert(sshprot == 0 || sshprot == 3);\r
3744     if (sshprot == 0)\r
3745         /* SSH-1 only */\r
3746         ssh->version = 1;\r
3747     if (sshprot == 3 && !ssh->bare_connection) {\r
3748         /* SSH-2 only */\r
3749         ssh->version = 2;\r
3750         ssh_send_verstring(ssh, "SSH-", NULL);\r
3751     }\r
3753     /*\r
3754      * loghost, if configured, overrides realhost.\r
3755      */\r
3756     if (*loghost) {\r
3757         sfree(*realhost);\r
3758         *realhost = dupstr(loghost);\r
3759     }\r
3761     return NULL;\r
3764 /*\r
3765  * Throttle or unthrottle the SSH connection.\r
3766  */\r
3767 static void ssh_throttle_conn(Ssh ssh, int adjust)\r
3769     int old_count = ssh->conn_throttle_count;\r
3770     ssh->conn_throttle_count += adjust;\r
3771     assert(ssh->conn_throttle_count >= 0);\r
3772     if (ssh->conn_throttle_count && !old_count) {\r
3773         ssh_set_frozen(ssh, 1);\r
3774     } else if (!ssh->conn_throttle_count && old_count) {\r
3775         ssh_set_frozen(ssh, 0);\r
3776     }\r
3779 static void ssh_agentf_try_forward(struct ssh_channel *c);\r
3781 /*\r
3782  * Throttle or unthrottle _all_ local data streams (for when sends\r
3783  * on the SSH connection itself back up).\r
3784  */\r
3785 static void ssh_throttle_all(Ssh ssh, int enable, int bufsize)\r
3787     int i;\r
3788     struct ssh_channel *c;\r
3790     if (enable == ssh->throttled_all)\r
3791         return;\r
3792     ssh->throttled_all = enable;\r
3793     ssh->overall_bufsize = bufsize;\r
3794     if (!ssh->channels)\r
3795         return;\r
3796     for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) {\r
3797         switch (c->type) {\r
3798           case CHAN_MAINSESSION:\r
3799             /*\r
3800              * This is treated separately, outside the switch.\r
3801              */\r
3802             break;\r
3803           case CHAN_X11:\r
3804             x11_override_throttle(c->u.x11.xconn, enable);\r
3805             break;\r
3806           case CHAN_AGENT:\r
3807             /* Agent forwarding channels are buffer-managed by\r
3808              * checking ssh->throttled_all in ssh_agentf_try_forward.\r
3809              * So at the moment we _un_throttle again, we must make an\r
3810              * attempt to do something. */\r
3811             if (!enable)\r
3812                 ssh_agentf_try_forward(c);\r
3813             break;\r
3814           case CHAN_SOCKDATA:\r
3815             pfd_override_throttle(c->u.pfd.pf, enable);\r
3816             break;\r
3817         }\r
3818     }\r
3821 static void ssh_agent_callback(void *sshv, void *reply, int replylen)\r
3823     Ssh ssh = (Ssh) sshv;\r
3825     ssh->auth_agent_query = NULL;\r
3827     ssh->agent_response = reply;\r
3828     ssh->agent_response_len = replylen;\r
3830     if (ssh->version == 1)\r
3831         do_ssh1_login(ssh, NULL, -1, NULL);\r
3832     else\r
3833         do_ssh2_authconn(ssh, NULL, -1, NULL);\r
3836 static void ssh_dialog_callback(void *sshv, int ret)\r
3838     Ssh ssh = (Ssh) sshv;\r
3840     ssh->user_response = ret;\r
3842     if (ssh->version == 1)\r
3843         do_ssh1_login(ssh, NULL, -1, NULL);\r
3844     else\r
3845         do_ssh2_transport(ssh, NULL, -1, NULL);\r
3847     /*\r
3848      * This may have unfrozen the SSH connection, so do a\r
3849      * queued-data run.\r
3850      */\r
3851     ssh_process_queued_incoming_data(ssh);\r
3854 static void ssh_agentf_got_response(struct ssh_channel *c,\r
3855                                     void *reply, int replylen)\r
3857     c->u.a.pending = NULL;\r
3859     assert(!(c->closes & CLOSES_SENT_EOF));\r
3861     if (!reply) {\r
3862         /* The real agent didn't send any kind of reply at all for\r
3863          * some reason, so fake an SSH_AGENT_FAILURE. */\r
3864         reply = "\0\0\0\1\5";\r
3865         replylen = 5;\r
3866     }\r
3868     ssh_send_channel_data(c, reply, replylen);\r
3871 static void ssh_agentf_callback(void *cv, void *reply, int replylen);\r
3873 static void ssh_agentf_try_forward(struct ssh_channel *c)\r
3875     unsigned datalen, lengthfield, messagelen;\r
3876     unsigned char *message;\r
3877     unsigned char msglen[4];\r
3878     void *reply;\r
3879     int replylen;\r
3881     /*\r
3882      * Don't try to parallelise agent requests. Wait for each one to\r
3883      * return before attempting the next.\r
3884      */\r
3885     if (c->u.a.pending)\r
3886         return;\r
3888     /*\r
3889      * If the outgoing side of the channel connection is currently\r
3890      * throttled (for any reason, either that channel's window size or\r
3891      * the entire SSH connection being throttled), don't submit any\r
3892      * new forwarded requests to the real agent. This causes the input\r
3893      * side of the agent forwarding not to be emptied, exerting the\r
3894      * required back-pressure on the remote client, and encouraging it\r
3895      * to read our responses before sending too many more requests.\r
3896      */\r
3897     if (c->ssh->throttled_all ||\r
3898         (c->ssh->version == 2 && c->v.v2.remwindow == 0))\r
3899         return;\r
3901     if (c->closes & CLOSES_SENT_EOF) {\r
3902         /*\r
3903          * If we've already sent outgoing EOF, there's nothing we can\r
3904          * do with incoming data except consume it and throw it away.\r
3905          */\r
3906         bufchain_clear(&c->u.a.inbuffer);\r
3907         return;\r
3908     }\r
3910     while (1) {\r
3911         /*\r
3912          * Try to extract a complete message from the input buffer.\r
3913          */\r
3914         datalen = bufchain_size(&c->u.a.inbuffer);\r
3915         if (datalen < 4)\r
3916             break;         /* not even a length field available yet */\r
3918         bufchain_fetch(&c->u.a.inbuffer, msglen, 4);\r
3919         lengthfield = GET_32BIT(msglen);\r
3921         if (lengthfield > AGENT_MAX_MSGLEN) {\r
3922             /*\r
3923              * If the remote has sent a message that's just _too_\r
3924              * long, we should reject it in advance of seeing the rest\r
3925              * of the incoming message, and also close the connection\r
3926              * for good measure (which avoids us having to faff about\r
3927              * with carefully ignoring just the right number of bytes\r
3928              * from the overlong message).\r
3929              */\r
3930             ssh_agentf_got_response(c, NULL, 0);\r
3931             sshfwd_write_eof(c);\r
3932             return;\r
3933         }\r
3935         if (lengthfield > datalen - 4)\r
3936             break;          /* a whole message is not yet available */\r
3938         messagelen = lengthfield + 4;\r
3940         message = snewn(messagelen, unsigned char);\r
3941         bufchain_fetch(&c->u.a.inbuffer, message, messagelen);\r
3942         bufchain_consume(&c->u.a.inbuffer, messagelen);\r
3943         c->u.a.pending = agent_query(\r
3944             message, messagelen, &reply, &replylen, ssh_agentf_callback, c);\r
3945         sfree(message);\r
3947         if (c->u.a.pending)\r
3948             return;   /* agent_query promised to reply in due course */\r
3950         /*\r
3951          * If the agent gave us an answer immediately, pass it\r
3952          * straight on and go round this loop again.\r
3953          */\r
3954         ssh_agentf_got_response(c, reply, replylen);\r
3955         sfree(reply);\r
3956     }\r
3958     /*\r
3959      * If we get here (i.e. we left the above while loop via 'break'\r
3960      * rather than 'return'), that means we've determined that the\r
3961      * input buffer for the agent forwarding connection doesn't\r
3962      * contain a complete request.\r
3963      *\r
3964      * So if there's potentially more data to come, we can return now,\r
3965      * and wait for the remote client to send it. But if the remote\r
3966      * has sent EOF, it would be a mistake to do that, because we'd be\r
3967      * waiting a long time. So this is the moment to check for EOF,\r
3968      * and respond appropriately.\r
3969      */\r
3970     if (c->closes & CLOSES_RCVD_EOF)\r
3971         sshfwd_write_eof(c);\r
3974 static void ssh_agentf_callback(void *cv, void *reply, int replylen)\r
3976     struct ssh_channel *c = (struct ssh_channel *)cv;\r
3978     ssh_agentf_got_response(c, reply, replylen);\r
3979     sfree(reply);\r
3981     /*\r
3982      * Now try to extract and send further messages from the channel's\r
3983      * input-side buffer.\r
3984      */\r
3985     ssh_agentf_try_forward(c);\r
3988 /*\r
3989  * Client-initiated disconnection. Send a DISCONNECT if `wire_reason'\r
3990  * non-NULL, otherwise just close the connection. `client_reason' == NULL\r
3991  * => log `wire_reason'.\r
3992  */\r
3993 static void ssh_disconnect(Ssh ssh, const char *client_reason,\r
3994                            const char *wire_reason,\r
3995                            int code, int clean_exit)\r
3997     char *error;\r
3998     if (!client_reason)\r
3999         client_reason = wire_reason;\r
4000     if (client_reason)\r
4001         error = dupprintf("Disconnected: %s", client_reason);\r
4002     else\r
4003         error = dupstr("Disconnected");\r
4004     if (wire_reason) {\r
4005         if (ssh->version == 1) {\r
4006             send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason,\r
4007                         PKT_END);\r
4008         } else if (ssh->version == 2) {\r
4009             struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT);\r
4010             ssh2_pkt_adduint32(pktout, code);\r
4011             ssh2_pkt_addstring(pktout, wire_reason);\r
4012             ssh2_pkt_addstring(pktout, "en");   /* language tag */\r
4013             ssh2_pkt_send_noqueue(ssh, pktout);\r
4014         }\r
4015     }\r
4016     ssh->close_expected = TRUE;\r
4017     ssh->clean_exit = clean_exit;\r
4018     ssh_closing((Plug)ssh, error, 0, 0);\r
4019     sfree(error);\r
4022 int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint,\r
4023                                const struct ssh_signkey *ssh2keytype,\r
4024                                void *ssh2keydata)\r
4026     if (!conf_get_str_nthstrkey(ssh->conf, CONF_ssh_manual_hostkeys, 0)) {\r
4027         return -1;                     /* no manual keys configured */\r
4028     }\r
4030     if (fingerprint) {\r
4031         /*\r
4032          * The fingerprint string we've been given will have things\r
4033          * like 'ssh-rsa 2048' at the front of it. Strip those off and\r
4034          * narrow down to just the colon-separated hex block at the\r
4035          * end of the string.\r
4036          */\r
4037         const char *p = strrchr(fingerprint, ' ');\r
4038         fingerprint = p ? p+1 : fingerprint;\r
4039         /* Quick sanity checks, including making sure it's in lowercase */\r
4040         assert(strlen(fingerprint) == 16*3 - 1);\r
4041         assert(fingerprint[2] == ':');\r
4042         assert(fingerprint[strspn(fingerprint, "0123456789abcdef:")] == 0);\r
4044         if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys,\r
4045                                  fingerprint))\r
4046             return 1;                  /* success */\r
4047     }\r
4049     if (ssh2keydata) {\r
4050         /*\r
4051          * Construct the base64-encoded public key blob and see if\r
4052          * that's listed.\r
4053          */\r
4054         unsigned char *binblob;\r
4055         char *base64blob;\r
4056         int binlen, atoms, i;\r
4057         binblob = ssh2keytype->public_blob(ssh2keydata, &binlen);\r
4058         atoms = (binlen + 2) / 3;\r
4059         base64blob = snewn(atoms * 4 + 1, char);\r
4060         for (i = 0; i < atoms; i++)\r
4061             base64_encode_atom(binblob + 3*i, binlen - 3*i, base64blob + 4*i);\r
4062         base64blob[atoms * 4] = '\0';\r
4063         sfree(binblob);\r
4064         if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys,\r
4065                                  base64blob)) {\r
4066             sfree(base64blob);\r
4067             return 1;                  /* success */\r
4068         }\r
4069         sfree(base64blob);\r
4070     }\r
4072     return 0;\r
4075 /*\r
4076  * Handle the key exchange and user authentication phases.\r
4077  */\r
4078 static int do_ssh1_login(Ssh ssh, const unsigned char *in, int inlen,\r
4079                          struct Packet *pktin)\r
4081     int i, j, ret;\r
4082     unsigned char cookie[8], *ptr;\r
4083     struct MD5Context md5c;\r
4084     struct do_ssh1_login_state {\r
4085         int crLine;\r
4086         int len;\r
4087         unsigned char *rsabuf;\r
4088         const unsigned char *keystr1, *keystr2;\r
4089         unsigned long supported_ciphers_mask, supported_auths_mask;\r
4090         int tried_publickey, tried_agent;\r
4091         int tis_auth_refused, ccard_auth_refused;\r
4092         unsigned char session_id[16];\r
4093         int cipher_type;\r
4094         void *publickey_blob;\r
4095         int publickey_bloblen;\r
4096         char *publickey_comment;\r
4097         int privatekey_available, privatekey_encrypted;\r
4098         prompts_t *cur_prompt;\r
4099         char c;\r
4100         int pwpkt_type;\r
4101         unsigned char request[5], *response, *p;\r
4102         int responselen;\r
4103         int keyi, nkeys;\r
4104         int authed;\r
4105         struct RSAKey key;\r
4106         Bignum challenge;\r
4107         char *commentp;\r
4108         int commentlen;\r
4109         int dlgret;\r
4110         Filename *keyfile;\r
4111         struct RSAKey servkey, hostkey;\r
4112     };\r
4113     crState(do_ssh1_login_state);\r
4115     crBeginState;\r
4117     if (!pktin)\r
4118         crWaitUntil(pktin);\r
4120     if (pktin->type != SSH1_SMSG_PUBLIC_KEY) {\r
4121         bombout(("Public key packet not received"));\r
4122         crStop(0);\r
4123     }\r
4125     logevent("Received public keys");\r
4127     ptr = ssh_pkt_getdata(pktin, 8);\r
4128     if (!ptr) {\r
4129         bombout(("SSH-1 public key packet stopped before random cookie"));\r
4130         crStop(0);\r
4131     }\r
4132     memcpy(cookie, ptr, 8);\r
4134     if (!ssh1_pkt_getrsakey(pktin, &s->servkey, &s->keystr1) ||\r
4135         !ssh1_pkt_getrsakey(pktin, &s->hostkey, &s->keystr2)) { \r
4136         bombout(("Failed to read SSH-1 public keys from public key packet"));\r
4137         crStop(0);\r
4138     }\r
4140     /*\r
4141      * Log the host key fingerprint.\r
4142      */\r
4143     {\r
4144         char logmsg[80];\r
4145         logevent("Host key fingerprint is:");\r
4146         strcpy(logmsg, "      ");\r
4147         s->hostkey.comment = NULL;\r
4148         rsa_fingerprint(logmsg + strlen(logmsg),\r
4149                         sizeof(logmsg) - strlen(logmsg), &s->hostkey);\r
4150         logevent(logmsg);\r
4151     }\r
4153     ssh->v1_remote_protoflags = ssh_pkt_getuint32(pktin);\r
4154     s->supported_ciphers_mask = ssh_pkt_getuint32(pktin);\r
4155     s->supported_auths_mask = ssh_pkt_getuint32(pktin);\r
4156     if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA))\r
4157         s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA);\r
4159     ssh->v1_local_protoflags =\r
4160         ssh->v1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED;\r
4161     ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;\r
4163     MD5Init(&md5c);\r
4164     MD5Update(&md5c, s->keystr2, s->hostkey.bytes);\r
4165     MD5Update(&md5c, s->keystr1, s->servkey.bytes);\r
4166     MD5Update(&md5c, cookie, 8);\r
4167     MD5Final(s->session_id, &md5c);\r
4169     for (i = 0; i < 32; i++)\r
4170         ssh->session_key[i] = random_byte();\r
4172     /*\r
4173      * Verify that the `bits' and `bytes' parameters match.\r
4174      */\r
4175     if (s->hostkey.bits > s->hostkey.bytes * 8 ||\r
4176         s->servkey.bits > s->servkey.bytes * 8) {\r
4177         bombout(("SSH-1 public keys were badly formatted"));\r
4178         crStop(0);\r
4179     }\r
4181     s->len = (s->hostkey.bytes > s->servkey.bytes ?\r
4182               s->hostkey.bytes : s->servkey.bytes);\r
4184     s->rsabuf = snewn(s->len, unsigned char);\r
4186     /*\r
4187      * Verify the host key.\r
4188      */\r
4189     {\r
4190         /*\r
4191          * First format the key into a string.\r
4192          */\r
4193         int len = rsastr_len(&s->hostkey);\r
4194         char fingerprint[100];\r
4195         char *keystr = snewn(len, char);\r
4196         rsastr_fmt(keystr, &s->hostkey);\r
4197         rsa_fingerprint(fingerprint, sizeof(fingerprint), &s->hostkey);\r
4199         /* First check against manually configured host keys. */\r
4200         s->dlgret = verify_ssh_manual_host_key(ssh, fingerprint, NULL, NULL);\r
4201         if (s->dlgret == 0) {          /* did not match */\r
4202             bombout(("Host key did not appear in manually configured list"));\r
4203             sfree(keystr);\r
4204             crStop(0);\r
4205         } else if (s->dlgret < 0) { /* none configured; use standard handling */\r
4206             ssh_set_frozen(ssh, 1);\r
4207             s->dlgret = verify_ssh_host_key(ssh->frontend,\r
4208                                             ssh->savedhost, ssh->savedport,\r
4209                                             "rsa", keystr, fingerprint,\r
4210                                             ssh_dialog_callback, ssh);\r
4211             sfree(keystr);\r
4212 #ifdef FUZZING\r
4213             s->dlgret = 1;\r
4214 #endif\r
4215             if (s->dlgret < 0) {\r
4216                 do {\r
4217                     crReturn(0);\r
4218                     if (pktin) {\r
4219                         bombout(("Unexpected data from server while waiting"\r
4220                                  " for user host key response"));\r
4221                         crStop(0);\r
4222                     }\r
4223                 } while (pktin || inlen > 0);\r
4224                 s->dlgret = ssh->user_response;\r
4225             }\r
4226             ssh_set_frozen(ssh, 0);\r
4228             if (s->dlgret == 0) {\r
4229                 ssh_disconnect(ssh, "User aborted at host key verification",\r
4230                                NULL, 0, TRUE);\r
4231                 crStop(0);\r
4232             }\r
4233         } else {\r
4234             sfree(keystr);\r
4235         }\r
4236     }\r
4238     for (i = 0; i < 32; i++) {\r
4239         s->rsabuf[i] = ssh->session_key[i];\r
4240         if (i < 16)\r
4241             s->rsabuf[i] ^= s->session_id[i];\r
4242     }\r
4244     if (s->hostkey.bytes > s->servkey.bytes) {\r
4245         ret = rsaencrypt(s->rsabuf, 32, &s->servkey);\r
4246         if (ret)\r
4247             ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);\r
4248     } else {\r
4249         ret = rsaencrypt(s->rsabuf, 32, &s->hostkey);\r
4250         if (ret)\r
4251             ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);\r
4252     }\r
4253     if (!ret) {\r
4254         bombout(("SSH-1 public key encryptions failed due to bad formatting"));\r
4255         crStop(0);      \r
4256     }\r
4258     logevent("Encrypted session key");\r
4260     {\r
4261         int cipher_chosen = 0, warn = 0;\r
4262         const char *cipher_string = NULL;\r
4263         int i;\r
4264         for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) {\r
4265             int next_cipher = conf_get_int_int(ssh->conf,\r
4266                                                CONF_ssh_cipherlist, i);\r
4267             if (next_cipher == CIPHER_WARN) {\r
4268                 /* If/when we choose a cipher, warn about it */\r
4269                 warn = 1;\r
4270             } else if (next_cipher == CIPHER_AES) {\r
4271                 /* XXX Probably don't need to mention this. */\r
4272                 logevent("AES not supported in SSH-1, skipping");\r
4273             } else {\r
4274                 switch (next_cipher) {\r
4275                   case CIPHER_3DES:     s->cipher_type = SSH_CIPHER_3DES;\r
4276                                         cipher_string = "3DES"; break;\r
4277                   case CIPHER_BLOWFISH: s->cipher_type = SSH_CIPHER_BLOWFISH;\r
4278                                         cipher_string = "Blowfish"; break;\r
4279                   case CIPHER_DES:      s->cipher_type = SSH_CIPHER_DES;\r
4280                                         cipher_string = "single-DES"; break;\r
4281                 }\r
4282                 if (s->supported_ciphers_mask & (1 << s->cipher_type))\r
4283                     cipher_chosen = 1;\r
4284             }\r
4285         }\r
4286         if (!cipher_chosen) {\r
4287             if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0)\r
4288                 bombout(("Server violates SSH-1 protocol by not "\r
4289                          "supporting 3DES encryption"));\r
4290             else\r
4291                 /* shouldn't happen */\r
4292                 bombout(("No supported ciphers found"));\r
4293             crStop(0);\r
4294         }\r
4296         /* Warn about chosen cipher if necessary. */\r
4297         if (warn) {\r
4298             ssh_set_frozen(ssh, 1);\r
4299             s->dlgret = askalg(ssh->frontend, "cipher", cipher_string,\r
4300                                ssh_dialog_callback, ssh);\r
4301             if (s->dlgret < 0) {\r
4302                 do {\r
4303                     crReturn(0);\r
4304                     if (pktin) {\r
4305                         bombout(("Unexpected data from server while waiting"\r
4306                                  " for user response"));\r
4307                         crStop(0);\r
4308                     }\r
4309                 } while (pktin || inlen > 0);\r
4310                 s->dlgret = ssh->user_response;\r
4311             }\r
4312             ssh_set_frozen(ssh, 0);\r
4313             if (s->dlgret == 0) {\r
4314                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
4315                                0, TRUE);\r
4316                 crStop(0);\r
4317             }\r
4318         }\r
4319     }\r
4321     switch (s->cipher_type) {\r
4322       case SSH_CIPHER_3DES:\r
4323         logevent("Using 3DES encryption");\r
4324         break;\r
4325       case SSH_CIPHER_DES:\r
4326         logevent("Using single-DES encryption");\r
4327         break;\r
4328       case SSH_CIPHER_BLOWFISH:\r
4329         logevent("Using Blowfish encryption");\r
4330         break;\r
4331     }\r
4333     send_packet(ssh, SSH1_CMSG_SESSION_KEY,\r
4334                 PKT_CHAR, s->cipher_type,\r
4335                 PKT_DATA, cookie, 8,\r
4336                 PKT_CHAR, (s->len * 8) >> 8, PKT_CHAR, (s->len * 8) & 0xFF,\r
4337                 PKT_DATA, s->rsabuf, s->len,\r
4338                 PKT_INT, ssh->v1_local_protoflags, PKT_END);\r
4340     logevent("Trying to enable encryption...");\r
4342     sfree(s->rsabuf);\r
4344     ssh->cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :\r
4345                    s->cipher_type == SSH_CIPHER_DES ? &ssh_des :\r
4346                    &ssh_3des);\r
4347     ssh->v1_cipher_ctx = ssh->cipher->make_context();\r
4348     ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key);\r
4349     logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name);\r
4351     ssh->crcda_ctx = crcda_make_context();\r
4352     logevent("Installing CRC compensation attack detector");\r
4354     if (s->servkey.modulus) {\r
4355         sfree(s->servkey.modulus);\r
4356         s->servkey.modulus = NULL;\r
4357     }\r
4358     if (s->servkey.exponent) {\r
4359         sfree(s->servkey.exponent);\r
4360         s->servkey.exponent = NULL;\r
4361     }\r
4362     if (s->hostkey.modulus) {\r
4363         sfree(s->hostkey.modulus);\r
4364         s->hostkey.modulus = NULL;\r
4365     }\r
4366     if (s->hostkey.exponent) {\r
4367         sfree(s->hostkey.exponent);\r
4368         s->hostkey.exponent = NULL;\r
4369     }\r
4370     crWaitUntil(pktin);\r
4372     if (pktin->type != SSH1_SMSG_SUCCESS) {\r
4373         bombout(("Encryption not successfully enabled"));\r
4374         crStop(0);\r
4375     }\r
4377     logevent("Successfully started encryption");\r
4379     fflush(stdout); /* FIXME eh? */\r
4380     {\r
4381         if ((ssh->username = get_remote_username(ssh->conf)) == NULL) {\r
4382             int ret; /* need not be kept over crReturn */\r
4383             s->cur_prompt = new_prompts(ssh->frontend);\r
4384             s->cur_prompt->to_server = TRUE;\r
4385             s->cur_prompt->name = dupstr("SSH login name");\r
4386             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);\r
4387             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
4388             while (ret < 0) {\r
4389                 ssh->send_ok = 1;\r
4390                 crWaitUntil(!pktin);\r
4391                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
4392                 ssh->send_ok = 0;\r
4393             }\r
4394             if (!ret) {\r
4395                 /*\r
4396                  * Failed to get a username. Terminate.\r
4397                  */\r
4398                 free_prompts(s->cur_prompt);\r
4399                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
4400                 crStop(0);\r
4401             }\r
4402             ssh->username = dupstr(s->cur_prompt->prompts[0]->result);\r
4403             free_prompts(s->cur_prompt);\r
4404         }\r
4406         send_packet(ssh, SSH1_CMSG_USER, PKT_STR, ssh->username, PKT_END);\r
4407         {\r
4408             char *userlog = dupprintf("Sent username \"%s\"", ssh->username);\r
4409             logevent(userlog);\r
4410             if (flags & FLAG_INTERACTIVE &&\r
4411                 (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {\r
4412                 c_write_str(ssh, userlog);\r
4413                 c_write_str(ssh, "\r\n");\r
4414             }\r
4415             sfree(userlog);\r
4416         }\r
4417     }\r
4419     crWaitUntil(pktin);\r
4421     if ((s->supported_auths_mask & (1 << SSH1_AUTH_RSA)) == 0) {\r
4422         /* We must not attempt PK auth. Pretend we've already tried it. */\r
4423         s->tried_publickey = s->tried_agent = 1;\r
4424     } else {\r
4425         s->tried_publickey = s->tried_agent = 0;\r
4426     }\r
4427     s->tis_auth_refused = s->ccard_auth_refused = 0;\r
4428     /*\r
4429      * Load the public half of any configured keyfile for later use.\r
4430      */\r
4431     s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
4432     if (!filename_is_null(s->keyfile)) {\r
4433         int keytype;\r
4434         logeventf(ssh, "Reading key file \"%.150s\"",\r
4435                   filename_to_str(s->keyfile));\r
4436         keytype = key_type(s->keyfile);\r
4437         if (keytype == SSH_KEYTYPE_SSH1 ||\r
4438             keytype == SSH_KEYTYPE_SSH1_PUBLIC) {\r
4439             const char *error;\r
4440             if (rsakey_pubblob(s->keyfile,\r
4441                                &s->publickey_blob, &s->publickey_bloblen,\r
4442                                &s->publickey_comment, &error)) {\r
4443                 s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1);\r
4444                 if (!s->privatekey_available)\r
4445                     logeventf(ssh, "Key file contains public key only");\r
4446                 s->privatekey_encrypted = rsakey_encrypted(s->keyfile,\r
4447                                                            NULL);\r
4448             } else {\r
4449                 char *msgbuf;\r
4450                 logeventf(ssh, "Unable to load key (%s)", error);\r
4451                 msgbuf = dupprintf("Unable to load key file "\r
4452                                    "\"%.150s\" (%s)\r\n",\r
4453                                    filename_to_str(s->keyfile),\r
4454                                    error);\r
4455                 c_write_str(ssh, msgbuf);\r
4456                 sfree(msgbuf);\r
4457                 s->publickey_blob = NULL;\r
4458             }\r
4459         } else {\r
4460             char *msgbuf;\r
4461             logeventf(ssh, "Unable to use this key file (%s)",\r
4462                       key_type_to_str(keytype));\r
4463             msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
4464                                " (%s)\r\n",\r
4465                                filename_to_str(s->keyfile),\r
4466                                key_type_to_str(keytype));\r
4467             c_write_str(ssh, msgbuf);\r
4468             sfree(msgbuf);\r
4469             s->publickey_blob = NULL;\r
4470         }\r
4471     } else\r
4472         s->publickey_blob = NULL;\r
4474     while (pktin->type == SSH1_SMSG_FAILURE) {\r
4475         s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;\r
4477         if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists() && !s->tried_agent) {\r
4478             /*\r
4479              * Attempt RSA authentication using Pageant.\r
4480              */\r
4481             void *r;\r
4483             s->authed = FALSE;\r
4484             s->tried_agent = 1;\r
4485             logevent("Pageant is running. Requesting keys.");\r
4487             /* Request the keys held by the agent. */\r
4488             PUT_32BIT(s->request, 1);\r
4489             s->request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;\r
4490             ssh->auth_agent_query = agent_query(\r
4491                 s->request, 5, &r, &s->responselen, ssh_agent_callback, ssh);\r
4492             if (ssh->auth_agent_query) {\r
4493                 do {\r
4494                     crReturn(0);\r
4495                     if (pktin) {\r
4496                         bombout(("Unexpected data from server while waiting"\r
4497                                  " for agent response"));\r
4498                         crStop(0);\r
4499                     }\r
4500                 } while (pktin || inlen > 0);\r
4501                 r = ssh->agent_response;\r
4502                 s->responselen = ssh->agent_response_len;\r
4503             }\r
4504             s->response = (unsigned char *) r;\r
4505             if (s->response && s->responselen >= 5 &&\r
4506                 s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {\r
4507                 s->p = s->response + 5;\r
4508                 s->nkeys = toint(GET_32BIT(s->p));\r
4509                 if (s->nkeys < 0) {\r
4510                     logeventf(ssh, "Pageant reported negative key count %d",\r
4511                               s->nkeys);\r
4512                     s->nkeys = 0;\r
4513                 }\r
4514                 s->p += 4;\r
4515                 logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys);\r
4516                 for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {\r
4517                     unsigned char *pkblob = s->p;\r
4518                     s->p += 4;\r
4519                     {\r
4520                         int n, ok = FALSE;\r
4521                         do {           /* do while (0) to make breaking easy */\r
4522                             n = ssh1_read_bignum\r
4523                                 (s->p, toint(s->responselen-(s->p-s->response)),\r
4524                                  &s->key.exponent);\r
4525                             if (n < 0)\r
4526                                 break;\r
4527                             s->p += n;\r
4528                             n = ssh1_read_bignum\r
4529                                 (s->p, toint(s->responselen-(s->p-s->response)),\r
4530                                  &s->key.modulus);\r
4531                             if (n < 0)\r
4532                                 break;\r
4533                             s->p += n;\r
4534                             if (s->responselen - (s->p-s->response) < 4)\r
4535                                 break;\r
4536                             s->commentlen = toint(GET_32BIT(s->p));\r
4537                             s->p += 4;\r
4538                             if (s->commentlen < 0 ||\r
4539                                 toint(s->responselen - (s->p-s->response)) <\r
4540                                 s->commentlen)\r
4541                                 break;\r
4542                             s->commentp = (char *)s->p;\r
4543                             s->p += s->commentlen;\r
4544                             ok = TRUE;\r
4545                         } while (0);\r
4546                         if (!ok) {\r
4547                             logevent("Pageant key list packet was truncated");\r
4548                             break;\r
4549                         }\r
4550                     }\r
4551                     if (s->publickey_blob) {\r
4552                         if (!memcmp(pkblob, s->publickey_blob,\r
4553                                     s->publickey_bloblen)) {\r
4554                             logeventf(ssh, "Pageant key #%d matches "\r
4555                                       "configured key file", s->keyi);\r
4556                             s->tried_publickey = 1;\r
4557                         } else\r
4558                             /* Skip non-configured key */\r
4559                             continue;\r
4560                     }\r
4561                     logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
4562                     send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
4563                                 PKT_BIGNUM, s->key.modulus, PKT_END);\r
4564                     crWaitUntil(pktin);\r
4565                     if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
4566                         logevent("Key refused");\r
4567                         continue;\r
4568                     }\r
4569                     logevent("Received RSA challenge");\r
4570                     if ((s->challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
4571                         bombout(("Server's RSA challenge was badly formatted"));\r
4572                         crStop(0);\r
4573                     }\r
4575                     {\r
4576                         char *agentreq, *q, *ret;\r
4577                         void *vret;\r
4578                         int len, retlen;\r
4579                         len = 1 + 4;   /* message type, bit count */\r
4580                         len += ssh1_bignum_length(s->key.exponent);\r
4581                         len += ssh1_bignum_length(s->key.modulus);\r
4582                         len += ssh1_bignum_length(s->challenge);\r
4583                         len += 16;     /* session id */\r
4584                         len += 4;      /* response format */\r
4585                         agentreq = snewn(4 + len, char);\r
4586                         PUT_32BIT(agentreq, len);\r
4587                         q = agentreq + 4;\r
4588                         *q++ = SSH1_AGENTC_RSA_CHALLENGE;\r
4589                         PUT_32BIT(q, bignum_bitcount(s->key.modulus));\r
4590                         q += 4;\r
4591                         q += ssh1_write_bignum(q, s->key.exponent);\r
4592                         q += ssh1_write_bignum(q, s->key.modulus);\r
4593                         q += ssh1_write_bignum(q, s->challenge);\r
4594                         memcpy(q, s->session_id, 16);\r
4595                         q += 16;\r
4596                         PUT_32BIT(q, 1);        /* response format */\r
4597                         ssh->auth_agent_query = agent_query(\r
4598                             agentreq, len + 4, &vret, &retlen,\r
4599                             ssh_agent_callback, ssh);\r
4600                         if (ssh->auth_agent_query) {\r
4601                             sfree(agentreq);\r
4602                             do {\r
4603                                 crReturn(0);\r
4604                                 if (pktin) {\r
4605                                     bombout(("Unexpected data from server"\r
4606                                              " while waiting for agent"\r
4607                                              " response"));\r
4608                                     crStop(0);\r
4609                                 }\r
4610                             } while (pktin || inlen > 0);\r
4611                             vret = ssh->agent_response;\r
4612                             retlen = ssh->agent_response_len;\r
4613                         } else\r
4614                             sfree(agentreq);\r
4615                         ret = vret;\r
4616                         if (ret) {\r
4617                             if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {\r
4618                                 logevent("Sending Pageant's response");\r
4619                                 send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
4620                                             PKT_DATA, ret + 5, 16,\r
4621                                             PKT_END);\r
4622                                 sfree(ret);\r
4623                                 crWaitUntil(pktin);\r
4624                                 if (pktin->type == SSH1_SMSG_SUCCESS) {\r
4625                                     logevent\r
4626                                         ("Pageant's response accepted");\r
4627                                     if (flags & FLAG_VERBOSE) {\r
4628                                         c_write_str(ssh, "Authenticated using"\r
4629                                                     " RSA key \"");\r
4630                                         c_write(ssh, s->commentp,\r
4631                                                 s->commentlen);\r
4632                                         c_write_str(ssh, "\" from agent\r\n");\r
4633                                     }\r
4634                                     s->authed = TRUE;\r
4635                                 } else\r
4636                                     logevent\r
4637                                         ("Pageant's response not accepted");\r
4638                             } else {\r
4639                                 logevent\r
4640                                     ("Pageant failed to answer challenge");\r
4641                                 sfree(ret);\r
4642                             }\r
4643                         } else {\r
4644                             logevent("No reply received from Pageant");\r
4645                         }\r
4646                     }\r
4647                     freebn(s->key.exponent);\r
4648                     freebn(s->key.modulus);\r
4649                     freebn(s->challenge);\r
4650                     if (s->authed)\r
4651                         break;\r
4652                 }\r
4653                 sfree(s->response);\r
4654                 if (s->publickey_blob && !s->tried_publickey)\r
4655                     logevent("Configured key file not in Pageant");\r
4656             } else {\r
4657                 logevent("Failed to get reply from Pageant");\r
4658             }\r
4659             if (s->authed)\r
4660                 break;\r
4661         }\r
4662         if (s->publickey_blob && s->privatekey_available &&\r
4663             !s->tried_publickey) {\r
4664             /*\r
4665              * Try public key authentication with the specified\r
4666              * key file.\r
4667              */\r
4668             int got_passphrase; /* need not be kept over crReturn */\r
4669             if (flags & FLAG_VERBOSE)\r
4670                 c_write_str(ssh, "Trying public key authentication.\r\n");\r
4671             s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
4672             logeventf(ssh, "Trying public key \"%s\"",\r
4673                       filename_to_str(s->keyfile));\r
4674             s->tried_publickey = 1;\r
4675             got_passphrase = FALSE;\r
4676             while (!got_passphrase) {\r
4677                 /*\r
4678                  * Get a passphrase, if necessary.\r
4679                  */\r
4680                 char *passphrase = NULL;    /* only written after crReturn */\r
4681                 const char *error;\r
4682                 if (!s->privatekey_encrypted) {\r
4683                     if (flags & FLAG_VERBOSE)\r
4684                         c_write_str(ssh, "No passphrase required.\r\n");\r
4685                     passphrase = NULL;\r
4686                 } else {\r
4687                     int ret; /* need not be kept over crReturn */\r
4688                     s->cur_prompt = new_prompts(ssh->frontend);\r
4689                     s->cur_prompt->to_server = FALSE;\r
4690                     s->cur_prompt->name = dupstr("SSH key passphrase");\r
4691                     add_prompt(s->cur_prompt,\r
4692                                dupprintf("Passphrase for key \"%.100s\": ",\r
4693                                          s->publickey_comment), FALSE);\r
4694                     ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
4695                     while (ret < 0) {\r
4696                         ssh->send_ok = 1;\r
4697                         crWaitUntil(!pktin);\r
4698                         ret = get_userpass_input(s->cur_prompt, in, inlen);\r
4699                         ssh->send_ok = 0;\r
4700                     }\r
4701                     if (!ret) {\r
4702                         /* Failed to get a passphrase. Terminate. */\r
4703                         free_prompts(s->cur_prompt);\r
4704                         ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
4705                                        0, TRUE);\r
4706                         crStop(0);\r
4707                     }\r
4708                     passphrase = dupstr(s->cur_prompt->prompts[0]->result);\r
4709                     free_prompts(s->cur_prompt);\r
4710                 }\r
4711                 /*\r
4712                  * Try decrypting key with passphrase.\r
4713                  */\r
4714                 s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
4715                 ret = loadrsakey(s->keyfile, &s->key, passphrase,\r
4716                                  &error);\r
4717                 if (passphrase) {\r
4718                     smemclr(passphrase, strlen(passphrase));\r
4719                     sfree(passphrase);\r
4720                 }\r
4721                 if (ret == 1) {\r
4722                     /* Correct passphrase. */\r
4723                     got_passphrase = TRUE;\r
4724                 } else if (ret == 0) {\r
4725                     c_write_str(ssh, "Couldn't load private key from ");\r
4726                     c_write_str(ssh, filename_to_str(s->keyfile));\r
4727                     c_write_str(ssh, " (");\r
4728                     c_write_str(ssh, error);\r
4729                     c_write_str(ssh, ").\r\n");\r
4730                     got_passphrase = FALSE;\r
4731                     break;             /* go and try something else */\r
4732                 } else if (ret == -1) {\r
4733                     c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */\r
4734                     got_passphrase = FALSE;\r
4735                     /* and try again */\r
4736                 } else {\r
4737                     assert(0 && "unexpected return from loadrsakey()");\r
4738                     got_passphrase = FALSE;   /* placate optimisers */\r
4739                 }\r
4740             }\r
4742             if (got_passphrase) {\r
4744                 /*\r
4745                  * Send a public key attempt.\r
4746                  */\r
4747                 send_packet(ssh, SSH1_CMSG_AUTH_RSA,\r
4748                             PKT_BIGNUM, s->key.modulus, PKT_END);\r
4750                 crWaitUntil(pktin);\r
4751                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
4752                     c_write_str(ssh, "Server refused our public key.\r\n");\r
4753                     continue;          /* go and try something else */\r
4754                 }\r
4755                 if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {\r
4756                     bombout(("Bizarre response to offer of public key"));\r
4757                     crStop(0);\r
4758                 }\r
4760                 {\r
4761                     int i;\r
4762                     unsigned char buffer[32];\r
4763                     Bignum challenge, response;\r
4765                     if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {\r
4766                         bombout(("Server's RSA challenge was badly formatted"));\r
4767                         crStop(0);\r
4768                     }\r
4769                     response = rsadecrypt(challenge, &s->key);\r
4770                     freebn(s->key.private_exponent);/* burn the evidence */\r
4772                     for (i = 0; i < 32; i++) {\r
4773                         buffer[i] = bignum_byte(response, 31 - i);\r
4774                     }\r
4776                     MD5Init(&md5c);\r
4777                     MD5Update(&md5c, buffer, 32);\r
4778                     MD5Update(&md5c, s->session_id, 16);\r
4779                     MD5Final(buffer, &md5c);\r
4781                     send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,\r
4782                                 PKT_DATA, buffer, 16, PKT_END);\r
4784                     freebn(challenge);\r
4785                     freebn(response);\r
4786                 }\r
4788                 crWaitUntil(pktin);\r
4789                 if (pktin->type == SSH1_SMSG_FAILURE) {\r
4790                     if (flags & FLAG_VERBOSE)\r
4791                         c_write_str(ssh, "Failed to authenticate with"\r
4792                                     " our public key.\r\n");\r
4793                     continue;          /* go and try something else */\r
4794                 } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
4795                     bombout(("Bizarre response to RSA authentication response"));\r
4796                     crStop(0);\r
4797                 }\r
4799                 break;                 /* we're through! */\r
4800             }\r
4802         }\r
4804         /*\r
4805          * Otherwise, try various forms of password-like authentication.\r
4806          */\r
4807         s->cur_prompt = new_prompts(ssh->frontend);\r
4809         if (conf_get_int(ssh->conf, CONF_try_tis_auth) &&\r
4810             (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&\r
4811             !s->tis_auth_refused) {\r
4812             s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;\r
4813             logevent("Requested TIS authentication");\r
4814             send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END);\r
4815             crWaitUntil(pktin);\r
4816             if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {\r
4817                 logevent("TIS authentication declined");\r
4818                 if (flags & FLAG_INTERACTIVE)\r
4819                     c_write_str(ssh, "TIS authentication refused.\r\n");\r
4820                 s->tis_auth_refused = 1;\r
4821                 continue;\r
4822             } else {\r
4823                 char *challenge;\r
4824                 int challengelen;\r
4825                 char *instr_suf, *prompt;\r
4827                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
4828                 if (!challenge) {\r
4829                     bombout(("TIS challenge packet was badly formed"));\r
4830                     crStop(0);\r
4831                 }\r
4832                 logevent("Received TIS challenge");\r
4833                 s->cur_prompt->to_server = TRUE;\r
4834                 s->cur_prompt->name = dupstr("SSH TIS authentication");\r
4835                 /* Prompt heuristic comes from OpenSSH */\r
4836                 if (memchr(challenge, '\n', challengelen)) {\r
4837                     instr_suf = dupstr("");\r
4838                     prompt = dupprintf("%.*s", challengelen, challenge);\r
4839                 } else {\r
4840                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
4841                     prompt = dupstr("Response: ");\r
4842                 }\r
4843                 s->cur_prompt->instruction =\r
4844                     dupprintf("Using TIS authentication.%s%s",\r
4845                               (*instr_suf) ? "\n" : "",\r
4846                               instr_suf);\r
4847                 s->cur_prompt->instr_reqd = TRUE;\r
4848                 add_prompt(s->cur_prompt, prompt, FALSE);\r
4849                 sfree(instr_suf);\r
4850             }\r
4851         }\r
4852         if (conf_get_int(ssh->conf, CONF_try_tis_auth) &&\r
4853             (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&\r
4854             !s->ccard_auth_refused) {\r
4855             s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;\r
4856             logevent("Requested CryptoCard authentication");\r
4857             send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END);\r
4858             crWaitUntil(pktin);\r
4859             if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {\r
4860                 logevent("CryptoCard authentication declined");\r
4861                 c_write_str(ssh, "CryptoCard authentication refused.\r\n");\r
4862                 s->ccard_auth_refused = 1;\r
4863                 continue;\r
4864             } else {\r
4865                 char *challenge;\r
4866                 int challengelen;\r
4867                 char *instr_suf, *prompt;\r
4869                 ssh_pkt_getstring(pktin, &challenge, &challengelen);\r
4870                 if (!challenge) {\r
4871                     bombout(("CryptoCard challenge packet was badly formed"));\r
4872                     crStop(0);\r
4873                 }\r
4874                 logevent("Received CryptoCard challenge");\r
4875                 s->cur_prompt->to_server = TRUE;\r
4876                 s->cur_prompt->name = dupstr("SSH CryptoCard authentication");\r
4877                 s->cur_prompt->name_reqd = FALSE;\r
4878                 /* Prompt heuristic comes from OpenSSH */\r
4879                 if (memchr(challenge, '\n', challengelen)) {\r
4880                     instr_suf = dupstr("");\r
4881                     prompt = dupprintf("%.*s", challengelen, challenge);\r
4882                 } else {\r
4883                     instr_suf = dupprintf("%.*s", challengelen, challenge);\r
4884                     prompt = dupstr("Response: ");\r
4885                 }\r
4886                 s->cur_prompt->instruction =\r
4887                     dupprintf("Using CryptoCard authentication.%s%s",\r
4888                               (*instr_suf) ? "\n" : "",\r
4889                               instr_suf);\r
4890                 s->cur_prompt->instr_reqd = TRUE;\r
4891                 add_prompt(s->cur_prompt, prompt, FALSE);\r
4892                 sfree(instr_suf);\r
4893             }\r
4894         }\r
4895         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
4896             if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) {\r
4897                 bombout(("No supported authentication methods available"));\r
4898                 crStop(0);\r
4899             }\r
4900             s->cur_prompt->to_server = TRUE;\r
4901             s->cur_prompt->name = dupstr("SSH password");\r
4902             add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",\r
4903                                                 ssh->username, ssh->savedhost),\r
4904                        FALSE);\r
4905         }\r
4907         /*\r
4908          * Show password prompt, having first obtained it via a TIS\r
4909          * or CryptoCard exchange if we're doing TIS or CryptoCard\r
4910          * authentication.\r
4911          */\r
4912         {\r
4913             int ret; /* need not be kept over crReturn */\r
4914             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
4915             while (ret < 0) {\r
4916                 ssh->send_ok = 1;\r
4917                 crWaitUntil(!pktin);\r
4918                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
4919                 ssh->send_ok = 0;\r
4920             }\r
4921             if (!ret) {\r
4922                 /*\r
4923                  * Failed to get a password (for example\r
4924                  * because one was supplied on the command line\r
4925                  * which has already failed to work). Terminate.\r
4926                  */\r
4927                 free_prompts(s->cur_prompt);\r
4928                 ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE);\r
4929                 crStop(0);\r
4930             }\r
4931         }\r
4933         if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {\r
4934             /*\r
4935              * Defence against traffic analysis: we send a\r
4936              * whole bunch of packets containing strings of\r
4937              * different lengths. One of these strings is the\r
4938              * password, in a SSH1_CMSG_AUTH_PASSWORD packet.\r
4939              * The others are all random data in\r
4940              * SSH1_MSG_IGNORE packets. This way a passive\r
4941              * listener can't tell which is the password, and\r
4942              * hence can't deduce the password length.\r
4943              * \r
4944              * Anybody with a password length greater than 16\r
4945              * bytes is going to have enough entropy in their\r
4946              * password that a listener won't find it _that_\r
4947              * much help to know how long it is. So what we'll\r
4948              * do is:\r
4949              * \r
4950              *  - if password length < 16, we send 15 packets\r
4951              *    containing string lengths 1 through 15\r
4952              * \r
4953              *  - otherwise, we let N be the nearest multiple\r
4954              *    of 8 below the password length, and send 8\r
4955              *    packets containing string lengths N through\r
4956              *    N+7. This won't obscure the order of\r
4957              *    magnitude of the password length, but it will\r
4958              *    introduce a bit of extra uncertainty.\r
4959              * \r
4960              * A few servers can't deal with SSH1_MSG_IGNORE, at\r
4961              * least in this context. For these servers, we need\r
4962              * an alternative defence. We make use of the fact\r
4963              * that the password is interpreted as a C string:\r
4964              * so we can append a NUL, then some random data.\r
4965              * \r
4966              * A few servers can deal with neither SSH1_MSG_IGNORE\r
4967              * here _nor_ a padded password string.\r
4968              * For these servers we are left with no defences\r
4969              * against password length sniffing.\r
4970              */\r
4971             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) &&\r
4972                 !(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
4973                 /*\r
4974                  * The server can deal with SSH1_MSG_IGNORE, so\r
4975                  * we can use the primary defence.\r
4976                  */\r
4977                 int bottom, top, pwlen, i;\r
4978                 char *randomstr;\r
4980                 pwlen = strlen(s->cur_prompt->prompts[0]->result);\r
4981                 if (pwlen < 16) {\r
4982                     bottom = 0;    /* zero length passwords are OK! :-) */\r
4983                     top = 15;\r
4984                 } else {\r
4985                     bottom = pwlen & ~7;\r
4986                     top = bottom + 7;\r
4987                 }\r
4989                 assert(pwlen >= bottom && pwlen <= top);\r
4991                 randomstr = snewn(top + 1, char);\r
4993                 for (i = bottom; i <= top; i++) {\r
4994                     if (i == pwlen) {\r
4995                         defer_packet(ssh, s->pwpkt_type,\r
4996                                      PKT_STR,s->cur_prompt->prompts[0]->result,\r
4997                                      PKT_END);\r
4998                     } else {\r
4999                         for (j = 0; j < i; j++) {\r
5000                             do {\r
5001                                 randomstr[j] = random_byte();\r
5002                             } while (randomstr[j] == '\0');\r
5003                         }\r
5004                         randomstr[i] = '\0';\r
5005                         defer_packet(ssh, SSH1_MSG_IGNORE,\r
5006                                      PKT_STR, randomstr, PKT_END);\r
5007                     }\r
5008                 }\r
5009                 logevent("Sending password with camouflage packets");\r
5010                 ssh_pkt_defersend(ssh);\r
5011                 sfree(randomstr);\r
5012             } \r
5013             else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {\r
5014                 /*\r
5015                  * The server can't deal with SSH1_MSG_IGNORE\r
5016                  * but can deal with padded passwords, so we\r
5017                  * can use the secondary defence.\r
5018                  */\r
5019                 char string[64];\r
5020                 char *ss;\r
5021                 int len;\r
5023                 len = strlen(s->cur_prompt->prompts[0]->result);\r
5024                 if (len < sizeof(string)) {\r
5025                     ss = string;\r
5026                     strcpy(string, s->cur_prompt->prompts[0]->result);\r
5027                     len++;             /* cover the zero byte */\r
5028                     while (len < sizeof(string)) {\r
5029                         string[len++] = (char) random_byte();\r
5030                     }\r
5031                 } else {\r
5032                     ss = s->cur_prompt->prompts[0]->result;\r
5033                 }\r
5034                 logevent("Sending length-padded password");\r
5035                 send_packet(ssh, s->pwpkt_type,\r
5036                             PKT_INT, len, PKT_DATA, ss, len,\r
5037                             PKT_END);\r
5038             } else {\r
5039                 /*\r
5040                  * The server is believed unable to cope with\r
5041                  * any of our password camouflage methods.\r
5042                  */\r
5043                 int len;\r
5044                 len = strlen(s->cur_prompt->prompts[0]->result);\r
5045                 logevent("Sending unpadded password");\r
5046                 send_packet(ssh, s->pwpkt_type,\r
5047                             PKT_INT, len,\r
5048                             PKT_DATA, s->cur_prompt->prompts[0]->result, len,\r
5049                             PKT_END);\r
5050             }\r
5051         } else {\r
5052             send_packet(ssh, s->pwpkt_type,\r
5053                         PKT_STR, s->cur_prompt->prompts[0]->result,\r
5054                         PKT_END);\r
5055         }\r
5056         logevent("Sent password");\r
5057         free_prompts(s->cur_prompt);\r
5058         crWaitUntil(pktin);\r
5059         if (pktin->type == SSH1_SMSG_FAILURE) {\r
5060             if (flags & FLAG_VERBOSE)\r
5061                 c_write_str(ssh, "Access denied\r\n");\r
5062             logevent("Authentication refused");\r
5063         } else if (pktin->type != SSH1_SMSG_SUCCESS) {\r
5064             bombout(("Strange packet received, type %d", pktin->type));\r
5065             crStop(0);\r
5066         }\r
5067     }\r
5069     /* Clear up */\r
5070     if (s->publickey_blob) {\r
5071         sfree(s->publickey_blob);\r
5072         sfree(s->publickey_comment);\r
5073     }\r
5075     logevent("Authentication successful");\r
5077     crFinish(1);\r
5080 static void ssh_channel_try_eof(struct ssh_channel *c)\r
5082     Ssh ssh = c->ssh;\r
5083     assert(c->pending_eof);          /* precondition for calling us */\r
5084     if (c->halfopen)\r
5085         return;                 /* can't close: not even opened yet */\r
5086     if (ssh->version == 2 && bufchain_size(&c->v.v2.outbuffer) > 0)\r
5087         return;              /* can't send EOF: pending outgoing data */\r
5089     c->pending_eof = FALSE;            /* we're about to send it */\r
5090     if (ssh->version == 1) {\r
5091         send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,\r
5092                     PKT_END);\r
5093         c->closes |= CLOSES_SENT_EOF;\r
5094     } else {\r
5095         struct Packet *pktout;\r
5096         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);\r
5097         ssh2_pkt_adduint32(pktout, c->remoteid);\r
5098         ssh2_pkt_send(ssh, pktout);\r
5099         c->closes |= CLOSES_SENT_EOF;\r
5100         ssh2_channel_check_close(c);\r
5101     }\r
5104 Conf *sshfwd_get_conf(struct ssh_channel *c)\r
5106     Ssh ssh = c->ssh;\r
5107     return ssh->conf;\r
5110 void sshfwd_write_eof(struct ssh_channel *c)\r
5112     Ssh ssh = c->ssh;\r
5114     if (ssh->state == SSH_STATE_CLOSED)\r
5115         return;\r
5117     if (c->closes & CLOSES_SENT_EOF)\r
5118         return;\r
5120     c->pending_eof = TRUE;\r
5121     ssh_channel_try_eof(c);\r
5124 void sshfwd_unclean_close(struct ssh_channel *c, const char *err)\r
5126     Ssh ssh = c->ssh;\r
5127     char *reason;\r
5129     if (ssh->state == SSH_STATE_CLOSED)\r
5130         return;\r
5132     reason = dupprintf("due to local error: %s", err);\r
5133     ssh_channel_close_local(c, reason);\r
5134     sfree(reason);\r
5135     c->pending_eof = FALSE;   /* this will confuse a zombie channel */\r
5137     ssh2_channel_check_close(c);\r
5140 int sshfwd_write(struct ssh_channel *c, char *buf, int len)\r
5142     Ssh ssh = c->ssh;\r
5144     if (ssh->state == SSH_STATE_CLOSED)\r
5145         return 0;\r
5147     return ssh_send_channel_data(c, buf, len);\r
5150 void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)\r
5152     Ssh ssh = c->ssh;\r
5154     if (ssh->state == SSH_STATE_CLOSED)\r
5155         return;\r
5157     ssh_channel_unthrottle(c, bufsize);\r
5160 static void ssh_queueing_handler(Ssh ssh, struct Packet *pktin)\r
5162     struct queued_handler *qh = ssh->qhead;\r
5164     assert(qh != NULL);\r
5166     assert(pktin->type == qh->msg1 || pktin->type == qh->msg2);\r
5168     if (qh->msg1 > 0) {\r
5169         assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler);\r
5170         ssh->packet_dispatch[qh->msg1] = ssh->q_saved_handler1;\r
5171     }\r
5172     if (qh->msg2 > 0) {\r
5173         assert(ssh->packet_dispatch[qh->msg2] == ssh_queueing_handler);\r
5174         ssh->packet_dispatch[qh->msg2] = ssh->q_saved_handler2;\r
5175     }\r
5177     if (qh->next) {\r
5178         ssh->qhead = qh->next;\r
5180         if (ssh->qhead->msg1 > 0) {\r
5181             ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1];\r
5182             ssh->packet_dispatch[ssh->qhead->msg1] = ssh_queueing_handler;\r
5183         }\r
5184         if (ssh->qhead->msg2 > 0) {\r
5185             ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2];\r
5186             ssh->packet_dispatch[ssh->qhead->msg2] = ssh_queueing_handler;\r
5187         }\r
5188     } else {\r
5189         ssh->qhead = ssh->qtail = NULL;\r
5190     }\r
5192     qh->handler(ssh, pktin, qh->ctx);\r
5194     sfree(qh);\r
5197 static void ssh_queue_handler(Ssh ssh, int msg1, int msg2,\r
5198                               chandler_fn_t handler, void *ctx)\r
5200     struct queued_handler *qh;\r
5202     qh = snew(struct queued_handler);\r
5203     qh->msg1 = msg1;\r
5204     qh->msg2 = msg2;\r
5205     qh->handler = handler;\r
5206     qh->ctx = ctx;\r
5207     qh->next = NULL;\r
5209     if (ssh->qtail == NULL) {\r
5210         ssh->qhead = qh;\r
5212         if (qh->msg1 > 0) {\r
5213             ssh->q_saved_handler1 = ssh->packet_dispatch[ssh->qhead->msg1];\r
5214             ssh->packet_dispatch[qh->msg1] = ssh_queueing_handler;\r
5215         }\r
5216         if (qh->msg2 > 0) {\r
5217             ssh->q_saved_handler2 = ssh->packet_dispatch[ssh->qhead->msg2];\r
5218             ssh->packet_dispatch[qh->msg2] = ssh_queueing_handler;\r
5219         }\r
5220     } else {\r
5221         ssh->qtail->next = qh;\r
5222     }\r
5223     ssh->qtail = qh;\r
5226 static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx)\r
5228     struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx;\r
5230     if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS :\r
5231                         SSH2_MSG_REQUEST_SUCCESS)) {\r
5232         logeventf(ssh, "Remote port forwarding from %s enabled",\r
5233                   pf->sportdesc);\r
5234     } else {\r
5235         logeventf(ssh, "Remote port forwarding from %s refused",\r
5236                   pf->sportdesc);\r
5238         rpf = del234(ssh->rportfwds, pf);\r
5239         assert(rpf == pf);\r
5240         pf->pfrec->remote = NULL;\r
5241         free_rportfwd(pf);\r
5242     }\r
5245 int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport,\r
5246                                void *share_ctx)\r
5248     struct ssh_rportfwd *pf = snew(struct ssh_rportfwd);\r
5249     pf->dhost = NULL;\r
5250     pf->dport = 0;\r
5251     pf->share_ctx = share_ctx;\r
5252     pf->shost = dupstr(shost);\r
5253     pf->sport = sport;\r
5254     pf->sportdesc = NULL;\r
5255     if (!ssh->rportfwds) {\r
5256         assert(ssh->version == 2);\r
5257         ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);\r
5258     }\r
5259     if (add234(ssh->rportfwds, pf) != pf) {\r
5260         sfree(pf->shost);\r
5261         sfree(pf);\r
5262         return FALSE;\r
5263     }\r
5264     return TRUE;\r
5267 static void ssh_sharing_global_request_response(Ssh ssh, struct Packet *pktin,\r
5268                                                 void *ctx)\r
5270     share_got_pkt_from_server(ctx, pktin->type,\r
5271                               pktin->body, pktin->length);\r
5274 void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx)\r
5276     ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE,\r
5277                       ssh_sharing_global_request_response, share_ctx);\r
5280 static void ssh_setup_portfwd(Ssh ssh, Conf *conf)\r
5282     struct ssh_portfwd *epf;\r
5283     int i;\r
5284     char *key, *val;\r
5286     if (!ssh->portfwds) {\r
5287         ssh->portfwds = newtree234(ssh_portcmp);\r
5288     } else {\r
5289         /*\r
5290          * Go through the existing port forwardings and tag them\r
5291          * with status==DESTROY. Any that we want to keep will be\r
5292          * re-enabled (status==KEEP) as we go through the\r
5293          * configuration and find out which bits are the same as\r
5294          * they were before.\r
5295          */\r
5296         struct ssh_portfwd *epf;\r
5297         int i;\r
5298         for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
5299             epf->status = DESTROY;\r
5300     }\r
5302     for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);\r
5303          val != NULL;\r
5304          val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {\r
5305         char *kp, *kp2, *vp, *vp2;\r
5306         char address_family, type;\r
5307         int sport,dport,sserv,dserv;\r
5308         char *sports, *dports, *saddr, *host;\r
5310         kp = key;\r
5312         address_family = 'A';\r
5313         type = 'L';\r
5314         if (*kp == 'A' || *kp == '4' || *kp == '6')\r
5315             address_family = *kp++;\r
5316         if (*kp == 'L' || *kp == 'R')\r
5317             type = *kp++;\r
5319         if ((kp2 = host_strchr(kp, ':')) != NULL) {\r
5320             /*\r
5321              * There's a colon in the middle of the source port\r
5322              * string, which means that the part before it is\r
5323              * actually a source address.\r
5324              */\r
5325             char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp);\r
5326             saddr = host_strduptrim(saddr_tmp);\r
5327             sfree(saddr_tmp);\r
5328             sports = kp2+1;\r
5329         } else {\r
5330             saddr = NULL;\r
5331             sports = kp;\r
5332         }\r
5333         sport = atoi(sports);\r
5334         sserv = 0;\r
5335         if (sport == 0) {\r
5336             sserv = 1;\r
5337             sport = net_service_lookup(sports);\r
5338             if (!sport) {\r
5339                 logeventf(ssh, "Service lookup failed for source"\r
5340                           " port \"%s\"", sports);\r
5341             }\r
5342         }\r
5344         if (type == 'L' && !strcmp(val, "D")) {\r
5345             /* dynamic forwarding */\r
5346             host = NULL;\r
5347             dports = NULL;\r
5348             dport = -1;\r
5349             dserv = 0;\r
5350             type = 'D';\r
5351         } else {\r
5352             /* ordinary forwarding */\r
5353             vp = val;\r
5354             vp2 = vp + host_strcspn(vp, ":");\r
5355             host = dupprintf("%.*s", (int)(vp2 - vp), vp);\r
5356             if (*vp2)\r
5357                 vp2++;\r
5358             dports = vp2;\r
5359             dport = atoi(dports);\r
5360             dserv = 0;\r
5361             if (dport == 0) {\r
5362                 dserv = 1;\r
5363                 dport = net_service_lookup(dports);\r
5364                 if (!dport) {\r
5365                     logeventf(ssh, "Service lookup failed for destination"\r
5366                               " port \"%s\"", dports);\r
5367                 }\r
5368             }\r
5369         }\r
5371         if (sport && dport) {\r
5372             /* Set up a description of the source port. */\r
5373             struct ssh_portfwd *pfrec, *epfrec;\r
5375             pfrec = snew(struct ssh_portfwd);\r
5376             pfrec->type = type;\r
5377             pfrec->saddr = saddr;\r
5378             pfrec->sserv = sserv ? dupstr(sports) : NULL;\r
5379             pfrec->sport = sport;\r
5380             pfrec->daddr = host;\r
5381             pfrec->dserv = dserv ? dupstr(dports) : NULL;\r
5382             pfrec->dport = dport;\r
5383             pfrec->local = NULL;\r
5384             pfrec->remote = NULL;\r
5385             pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :\r
5386                                     address_family == '6' ? ADDRTYPE_IPV6 :\r
5387                                     ADDRTYPE_UNSPEC);\r
5389             epfrec = add234(ssh->portfwds, pfrec);\r
5390             if (epfrec != pfrec) {\r
5391                 if (epfrec->status == DESTROY) {\r
5392                     /*\r
5393                      * We already have a port forwarding up and running\r
5394                      * with precisely these parameters. Hence, no need\r
5395                      * to do anything; simply re-tag the existing one\r
5396                      * as KEEP.\r
5397                      */\r
5398                     epfrec->status = KEEP;\r
5399                 }\r
5400                 /*\r
5401                  * Anything else indicates that there was a duplicate\r
5402                  * in our input, which we'll silently ignore.\r
5403                  */\r
5404                 free_portfwd(pfrec);\r
5405             } else {\r
5406                 pfrec->status = CREATE;\r
5407             }\r
5408         } else {\r
5409             sfree(saddr);\r
5410             sfree(host);\r
5411         }\r
5412     }\r
5414     /*\r
5415      * Now go through and destroy any port forwardings which were\r
5416      * not re-enabled.\r
5417      */\r
5418     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
5419         if (epf->status == DESTROY) {\r
5420             char *message;\r
5422             message = dupprintf("%s port forwarding from %s%s%d",\r
5423                                 epf->type == 'L' ? "local" :\r
5424                                 epf->type == 'R' ? "remote" : "dynamic",\r
5425                                 epf->saddr ? epf->saddr : "",\r
5426                                 epf->saddr ? ":" : "",\r
5427                                 epf->sport);\r
5429             if (epf->type != 'D') {\r
5430                 char *msg2 = dupprintf("%s to %s:%d", message,\r
5431                                        epf->daddr, epf->dport);\r
5432                 sfree(message);\r
5433                 message = msg2;\r
5434             }\r
5436             logeventf(ssh, "Cancelling %s", message);\r
5437             sfree(message);\r
5439             /* epf->remote or epf->local may be NULL if setting up a\r
5440              * forwarding failed. */\r
5441             if (epf->remote) {\r
5442                 struct ssh_rportfwd *rpf = epf->remote;\r
5443                 struct Packet *pktout;\r
5445                 /*\r
5446                  * Cancel the port forwarding at the server\r
5447                  * end.\r
5448                  */\r
5449                 if (ssh->version == 1) {\r
5450                     /*\r
5451                      * We cannot cancel listening ports on the\r
5452                      * server side in SSH-1! There's no message\r
5453                      * to support it. Instead, we simply remove\r
5454                      * the rportfwd record from the local end\r
5455                      * so that any connections the server tries\r
5456                      * to make on it are rejected.\r
5457                      */\r
5458                 } else {\r
5459                     pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
5460                     ssh2_pkt_addstring(pktout, "cancel-tcpip-forward");\r
5461                     ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */\r
5462                     if (epf->saddr) {\r
5463                         ssh2_pkt_addstring(pktout, epf->saddr);\r
5464                     } else if (conf_get_int(conf, CONF_rport_acceptall)) {\r
5465                         /* XXX: rport_acceptall may not represent\r
5466                          * what was used to open the original connection,\r
5467                          * since it's reconfigurable. */\r
5468                         ssh2_pkt_addstring(pktout, "");\r
5469                     } else {\r
5470                         ssh2_pkt_addstring(pktout, "localhost");\r
5471                     }\r
5472                     ssh2_pkt_adduint32(pktout, epf->sport);\r
5473                     ssh2_pkt_send(ssh, pktout);\r
5474                 }\r
5476                 del234(ssh->rportfwds, rpf);\r
5477                 free_rportfwd(rpf);\r
5478             } else if (epf->local) {\r
5479                 pfl_terminate(epf->local);\r
5480             }\r
5482             delpos234(ssh->portfwds, i);\r
5483             free_portfwd(epf);\r
5484             i--;                       /* so we don't skip one in the list */\r
5485         }\r
5487     /*\r
5488      * And finally, set up any new port forwardings (status==CREATE).\r
5489      */\r
5490     for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)\r
5491         if (epf->status == CREATE) {\r
5492             char *sportdesc, *dportdesc;\r
5493             sportdesc = dupprintf("%s%s%s%s%d%s",\r
5494                                   epf->saddr ? epf->saddr : "",\r
5495                                   epf->saddr ? ":" : "",\r
5496                                   epf->sserv ? epf->sserv : "",\r
5497                                   epf->sserv ? "(" : "",\r
5498                                   epf->sport,\r
5499                                   epf->sserv ? ")" : "");\r
5500             if (epf->type == 'D') {\r
5501                 dportdesc = NULL;\r
5502             } else {\r
5503                 dportdesc = dupprintf("%s:%s%s%d%s",\r
5504                                       epf->daddr,\r
5505                                       epf->dserv ? epf->dserv : "",\r
5506                                       epf->dserv ? "(" : "",\r
5507                                       epf->dport,\r
5508                                       epf->dserv ? ")" : "");\r
5509             }\r
5511             if (epf->type == 'L') {\r
5512                 char *err = pfl_listen(epf->daddr, epf->dport,\r
5513                                        epf->saddr, epf->sport,\r
5514                                        ssh, conf, &epf->local,\r
5515                                        epf->addressfamily);\r
5517                 logeventf(ssh, "Local %sport %s forwarding to %s%s%s",\r
5518                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
5519                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
5520                           sportdesc, dportdesc,\r
5521                           err ? " failed: " : "", err ? err : "");\r
5522                 if (err)\r
5523                     sfree(err);\r
5524             } else if (epf->type == 'D') {\r
5525                 char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport,\r
5526                                        ssh, conf, &epf->local,\r
5527                                        epf->addressfamily);\r
5529                 logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",\r
5530                           epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :\r
5531                           epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",\r
5532                           sportdesc,\r
5533                           err ? " failed: " : "", err ? err : "");\r
5535                 if (err)\r
5536                     sfree(err);\r
5537             } else {\r
5538                 struct ssh_rportfwd *pf;\r
5540                 /*\r
5541                  * Ensure the remote port forwardings tree exists.\r
5542                  */\r
5543                 if (!ssh->rportfwds) {\r
5544                     if (ssh->version == 1)\r
5545                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);\r
5546                     else\r
5547                         ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);\r
5548                 }\r
5550                 pf = snew(struct ssh_rportfwd);\r
5551                 pf->share_ctx = NULL;\r
5552                 pf->dhost = dupstr(epf->daddr);\r
5553                 pf->dport = epf->dport;\r
5554                 if (epf->saddr) {\r
5555                     pf->shost = dupstr(epf->saddr);\r
5556                 } else if (conf_get_int(conf, CONF_rport_acceptall)) {\r
5557                     pf->shost = dupstr("");\r
5558                 } else {\r
5559                     pf->shost = dupstr("localhost");\r
5560                 }\r
5561                 pf->sport = epf->sport;\r
5562                 if (add234(ssh->rportfwds, pf) != pf) {\r
5563                     logeventf(ssh, "Duplicate remote port forwarding to %s:%d",\r
5564                               epf->daddr, epf->dport);\r
5565                     sfree(pf);\r
5566                 } else {\r
5567                     logeventf(ssh, "Requesting remote port %s"\r
5568                               " forward to %s", sportdesc, dportdesc);\r
5570                     pf->sportdesc = sportdesc;\r
5571                     sportdesc = NULL;\r
5572                     epf->remote = pf;\r
5573                     pf->pfrec = epf;\r
5575                     if (ssh->version == 1) {\r
5576                         send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST,\r
5577                                     PKT_INT, epf->sport,\r
5578                                     PKT_STR, epf->daddr,\r
5579                                     PKT_INT, epf->dport,\r
5580                                     PKT_END);\r
5581                         ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,\r
5582                                           SSH1_SMSG_FAILURE,\r
5583                                           ssh_rportfwd_succfail, pf);\r
5584                     } else {\r
5585                         struct Packet *pktout;\r
5586                         pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);\r
5587                         ssh2_pkt_addstring(pktout, "tcpip-forward");\r
5588                         ssh2_pkt_addbool(pktout, 1);/* want reply */\r
5589                         ssh2_pkt_addstring(pktout, pf->shost);\r
5590                         ssh2_pkt_adduint32(pktout, pf->sport);\r
5591                         ssh2_pkt_send(ssh, pktout);\r
5593                         ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,\r
5594                                           SSH2_MSG_REQUEST_FAILURE,\r
5595                                           ssh_rportfwd_succfail, pf);\r
5596                     }\r
5597                 }\r
5598             }\r
5599             sfree(sportdesc);\r
5600             sfree(dportdesc);\r
5601         }\r
5604 static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin)\r
5606     char *string;\r
5607     int stringlen, bufsize;\r
5609     ssh_pkt_getstring(pktin, &string, &stringlen);\r
5610     if (string == NULL) {\r
5611         bombout(("Incoming terminal data packet was badly formed"));\r
5612         return;\r
5613     }\r
5615     bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA,\r
5616                            string, stringlen);\r
5617     if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {\r
5618         ssh->v1_stdout_throttling = 1;\r
5619         ssh_throttle_conn(ssh, +1);\r
5620     }\r
5623 static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)\r
5625     /* Remote side is trying to open a channel to talk to our\r
5626      * X-Server. Give them back a local channel number. */\r
5627     struct ssh_channel *c;\r
5628     int remoteid = ssh_pkt_getuint32(pktin);\r
5630     logevent("Received X11 connect request");\r
5631     /* Refuse if X11 forwarding is disabled. */\r
5632     if (!ssh->X11_fwd_enabled) {\r
5633         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
5634                     PKT_INT, remoteid, PKT_END);\r
5635         logevent("Rejected X11 connect request");\r
5636     } else {\r
5637         c = snew(struct ssh_channel);\r
5638         c->ssh = ssh;\r
5640         ssh_channel_init(c);\r
5641         c->u.x11.xconn = x11_init(ssh->x11authtree, c, NULL, -1);\r
5642         c->remoteid = remoteid;\r
5643         c->halfopen = FALSE;\r
5644         c->type = CHAN_X11;     /* identify channel type */\r
5645         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
5646                     PKT_INT, c->remoteid, PKT_INT,\r
5647                     c->localid, PKT_END);\r
5648         logevent("Opened X11 forward channel");\r
5649     }\r
5652 static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)\r
5654     /* Remote side is trying to open a channel to talk to our\r
5655      * agent. Give them back a local channel number. */\r
5656     struct ssh_channel *c;\r
5657     int remoteid = ssh_pkt_getuint32(pktin);\r
5659     /* Refuse if agent forwarding is disabled. */\r
5660     if (!ssh->agentfwd_enabled) {\r
5661         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
5662                     PKT_INT, remoteid, PKT_END);\r
5663     } else {\r
5664         c = snew(struct ssh_channel);\r
5665         c->ssh = ssh;\r
5666         ssh_channel_init(c);\r
5667         c->remoteid = remoteid;\r
5668         c->halfopen = FALSE;\r
5669         c->type = CHAN_AGENT;   /* identify channel type */\r
5670         c->u.a.pending = NULL;\r
5671         bufchain_init(&c->u.a.inbuffer);\r
5672         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
5673                     PKT_INT, c->remoteid, PKT_INT, c->localid,\r
5674                     PKT_END);\r
5675     }\r
5678 static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)\r
5680     /* Remote side is trying to open a channel to talk to a\r
5681      * forwarded port. Give them back a local channel number. */\r
5682     struct ssh_rportfwd pf, *pfp;\r
5683     int remoteid;\r
5684     int hostsize, port;\r
5685     char *host;\r
5686     char *err;\r
5688     remoteid = ssh_pkt_getuint32(pktin);\r
5689     ssh_pkt_getstring(pktin, &host, &hostsize);\r
5690     port = ssh_pkt_getuint32(pktin);\r
5692     pf.dhost = dupprintf("%.*s", hostsize, NULLTOEMPTY(host));\r
5693     pf.dport = port;\r
5694     pfp = find234(ssh->rportfwds, &pf, NULL);\r
5696     if (pfp == NULL) {\r
5697         logeventf(ssh, "Rejected remote port open request for %s:%d",\r
5698                   pf.dhost, port);\r
5699         send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
5700                     PKT_INT, remoteid, PKT_END);\r
5701     } else {\r
5702         struct ssh_channel *c = snew(struct ssh_channel);\r
5703         c->ssh = ssh;\r
5705         logeventf(ssh, "Received remote port open request for %s:%d",\r
5706                   pf.dhost, port);\r
5707         err = pfd_connect(&c->u.pfd.pf, pf.dhost, port,\r
5708                           c, ssh->conf, pfp->pfrec->addressfamily);\r
5709         if (err != NULL) {\r
5710             logeventf(ssh, "Port open failed: %s", err);\r
5711             sfree(err);\r
5712             sfree(c);\r
5713             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,\r
5714                         PKT_INT, remoteid, PKT_END);\r
5715         } else {\r
5716             ssh_channel_init(c);\r
5717             c->remoteid = remoteid;\r
5718             c->halfopen = FALSE;\r
5719             c->type = CHAN_SOCKDATA;    /* identify channel type */\r
5720             send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,\r
5721                         PKT_INT, c->remoteid, PKT_INT,\r
5722                         c->localid, PKT_END);\r
5723             logevent("Forwarded port opened successfully");\r
5724         }\r
5725     }\r
5727     sfree(pf.dhost);\r
5730 static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
5732     struct ssh_channel *c;\r
5734     c = ssh_channel_msg(ssh, pktin);\r
5735     if (c && c->type == CHAN_SOCKDATA) {\r
5736         c->remoteid = ssh_pkt_getuint32(pktin);\r
5737         c->halfopen = FALSE;\r
5738         c->throttling_conn = 0;\r
5739         pfd_confirm(c->u.pfd.pf);\r
5740     }\r
5742     if (c && c->pending_eof) {\r
5743         /*\r
5744          * We have a pending close on this channel,\r
5745          * which we decided on before the server acked\r
5746          * the channel open. So now we know the\r
5747          * remoteid, we can close it again.\r
5748          */\r
5749         ssh_channel_try_eof(c);\r
5750     }\r
5753 static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
5755     struct ssh_channel *c;\r
5757     c = ssh_channel_msg(ssh, pktin);\r
5758     if (c && c->type == CHAN_SOCKDATA) {\r
5759         logevent("Forwarded connection refused by server");\r
5760         pfd_close(c->u.pfd.pf);\r
5761         del234(ssh->channels, c);\r
5762         sfree(c);\r
5763     }\r
5766 static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
5768     /* Remote side closes a channel. */\r
5769     struct ssh_channel *c;\r
5771     c = ssh_channel_msg(ssh, pktin);\r
5772     if (c) {\r
5774         if (pktin->type == SSH1_MSG_CHANNEL_CLOSE) {\r
5775             /*\r
5776              * Received CHANNEL_CLOSE, which we translate into\r
5777              * outgoing EOF.\r
5778              */\r
5779             ssh_channel_got_eof(c);\r
5780         }\r
5782         if (pktin->type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION &&\r
5783             !(c->closes & CLOSES_RCVD_CLOSE)) {\r
5785             if (!(c->closes & CLOSES_SENT_EOF)) {\r
5786                 bombout(("Received CHANNEL_CLOSE_CONFIRMATION for channel %u"\r
5787                          " for which we never sent CHANNEL_CLOSE\n",\r
5788                          c->localid));\r
5789             }\r
5791             c->closes |= CLOSES_RCVD_CLOSE;\r
5792         }\r
5794         if (!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) &&\r
5795             !(c->closes & CLOSES_SENT_CLOSE)) {\r
5796             send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION,\r
5797                         PKT_INT, c->remoteid, PKT_END);\r
5798             c->closes |= CLOSES_SENT_CLOSE;\r
5799         }\r
5801         if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes))\r
5802             ssh_channel_destroy(c);\r
5803     }\r
5806 /*\r
5807  * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel.\r
5808  */\r
5809 static int ssh_agent_channel_data(struct ssh_channel *c, char *data,\r
5810                                   int length)\r
5812     bufchain_add(&c->u.a.inbuffer, data, length);\r
5813     ssh_agentf_try_forward(c);\r
5815     /*\r
5816      * We exert back-pressure on an agent forwarding client if and\r
5817      * only if we're waiting for the response to an asynchronous agent\r
5818      * request. This prevents the client running out of window while\r
5819      * receiving the _first_ message, but means that if any message\r
5820      * takes time to process, the client will be discouraged from\r
5821      * sending an endless stream of further ones after it.\r
5822      */\r
5823     return (c->u.a.pending ? bufchain_size(&c->u.a.inbuffer) : 0);\r
5826 static int ssh_channel_data(struct ssh_channel *c, int is_stderr,\r
5827                             char *data,  int length)\r
5829     switch (c->type) {\r
5830       case CHAN_MAINSESSION:\r
5831         return from_backend(c->ssh->frontend, is_stderr, data, length);\r
5832       case CHAN_X11:\r
5833         return x11_send(c->u.x11.xconn, data, length);\r
5834       case CHAN_SOCKDATA:\r
5835         return pfd_send(c->u.pfd.pf, data, length);\r
5836       case CHAN_AGENT:\r
5837         return ssh_agent_channel_data(c, data, length);\r
5838     }\r
5839     return 0;\r
5842 static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
5844     /* Data sent down one of our channels. */\r
5845     char *p;\r
5846     int len;\r
5847     struct ssh_channel *c;\r
5849     c = ssh_channel_msg(ssh, pktin);\r
5850     ssh_pkt_getstring(pktin, &p, &len);\r
5852     if (c) {\r
5853         int bufsize = ssh_channel_data(c, FALSE, p, len);\r
5854         if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {\r
5855             c->throttling_conn = 1;\r
5856             ssh_throttle_conn(ssh, +1);\r
5857         }\r
5858     }\r
5861 static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin)\r
5863     ssh->exitcode = ssh_pkt_getuint32(pktin);\r
5864     logeventf(ssh, "Server sent command exit status %d", ssh->exitcode);\r
5865     send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);\r
5866     /*\r
5867      * In case `helpful' firewalls or proxies tack\r
5868      * extra human-readable text on the end of the\r
5869      * session which we might mistake for another\r
5870      * encrypted packet, we close the session once\r
5871      * we've sent EXIT_CONFIRMATION.\r
5872      */\r
5873     ssh_disconnect(ssh, NULL, NULL, 0, TRUE);\r
5876 /* Helper function to deal with sending tty modes for REQUEST_PTY */\r
5877 static void ssh1_send_ttymode(void *data,\r
5878                               const struct ssh_ttymode *mode, char *val)\r
5880     struct Packet *pktout = (struct Packet *)data;\r
5881     unsigned int arg = 0;\r
5883     switch (mode->type) {\r
5884       case TTY_OP_CHAR:\r
5885         arg = ssh_tty_parse_specchar(val);\r
5886         break;\r
5887       case TTY_OP_BOOL:\r
5888         arg = ssh_tty_parse_boolean(val);\r
5889         break;\r
5890     }\r
5891     ssh2_pkt_addbyte(pktout, mode->opcode);\r
5892     ssh2_pkt_addbyte(pktout, arg);\r
5895 int ssh_agent_forwarding_permitted(Ssh ssh)\r
5897     return conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists();\r
5900 static void do_ssh1_connection(Ssh ssh, const unsigned char *in, int inlen,\r
5901                                struct Packet *pktin)\r
5903     crBegin(ssh->do_ssh1_connection_crstate);\r
5905     ssh->packet_dispatch[SSH1_SMSG_STDOUT_DATA] = \r
5906         ssh->packet_dispatch[SSH1_SMSG_STDERR_DATA] =\r
5907         ssh1_smsg_stdout_stderr_data;\r
5909     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
5910         ssh1_msg_channel_open_confirmation;\r
5911     ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_FAILURE] =\r
5912         ssh1_msg_channel_open_failure;\r
5913     ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE] =\r
5914         ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION] =\r
5915         ssh1_msg_channel_close;\r
5916     ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data;\r
5917     ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status;\r
5919     if (ssh_agent_forwarding_permitted(ssh)) {\r
5920         logevent("Requesting agent forwarding");\r
5921         send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);\r
5922         do {\r
5923             crReturnV;\r
5924         } while (!pktin);\r
5925         if (pktin->type != SSH1_SMSG_SUCCESS\r
5926             && pktin->type != SSH1_SMSG_FAILURE) {\r
5927             bombout(("Protocol confusion"));\r
5928             crStopV;\r
5929         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5930             logevent("Agent forwarding refused");\r
5931         } else {\r
5932             logevent("Agent forwarding enabled");\r
5933             ssh->agentfwd_enabled = TRUE;\r
5934             ssh->packet_dispatch[SSH1_SMSG_AGENT_OPEN] = ssh1_smsg_agent_open;\r
5935         }\r
5936     }\r
5938     if (conf_get_int(ssh->conf, CONF_x11_forward)) {\r
5939         ssh->x11disp =\r
5940             x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),\r
5941                               ssh->conf);\r
5942         if (!ssh->x11disp) {\r
5943             /* FIXME: return an error message from x11_setup_display */\r
5944             logevent("X11 forwarding not enabled: unable to"\r
5945                      " initialise X display");\r
5946         } else {\r
5947             ssh->x11auth = x11_invent_fake_auth\r
5948                 (ssh->x11authtree, conf_get_int(ssh->conf, CONF_x11_auth));\r
5949             ssh->x11auth->disp = ssh->x11disp;\r
5951             logevent("Requesting X11 forwarding");\r
5952             if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {\r
5953                 send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5954                             PKT_STR, ssh->x11auth->protoname,\r
5955                             PKT_STR, ssh->x11auth->datastring,\r
5956                             PKT_INT, ssh->x11disp->screennum,\r
5957                             PKT_END);\r
5958             } else {\r
5959                 send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,\r
5960                             PKT_STR, ssh->x11auth->protoname,\r
5961                             PKT_STR, ssh->x11auth->datastring,\r
5962                             PKT_END);\r
5963             }\r
5964             do {\r
5965                 crReturnV;\r
5966             } while (!pktin);\r
5967             if (pktin->type != SSH1_SMSG_SUCCESS\r
5968                 && pktin->type != SSH1_SMSG_FAILURE) {\r
5969                 bombout(("Protocol confusion"));\r
5970                 crStopV;\r
5971             } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
5972                 logevent("X11 forwarding refused");\r
5973             } else {\r
5974                 logevent("X11 forwarding enabled");\r
5975                 ssh->X11_fwd_enabled = TRUE;\r
5976                 ssh->packet_dispatch[SSH1_SMSG_X11_OPEN] = ssh1_smsg_x11_open;\r
5977             }\r
5978         }\r
5979     }\r
5981     ssh_setup_portfwd(ssh, ssh->conf);\r
5982     ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open;\r
5984     if (!conf_get_int(ssh->conf, CONF_nopty)) {\r
5985         struct Packet *pkt;\r
5986         /* Unpick the terminal-speed string. */\r
5987         /* XXX perhaps we should allow no speeds to be sent. */\r
5988         ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
5989         sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
5990         /* Send the pty request. */\r
5991         pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY);\r
5992         ssh_pkt_addstring(pkt, conf_get_str(ssh->conf, CONF_termtype));\r
5993         ssh_pkt_adduint32(pkt, ssh->term_height);\r
5994         ssh_pkt_adduint32(pkt, ssh->term_width);\r
5995         ssh_pkt_adduint32(pkt, 0); /* width in pixels */\r
5996         ssh_pkt_adduint32(pkt, 0); /* height in pixels */\r
5997         parse_ttymodes(ssh, ssh1_send_ttymode, (void *)pkt);\r
5998         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_ISPEED);\r
5999         ssh_pkt_adduint32(pkt, ssh->ispeed);\r
6000         ssh_pkt_addbyte(pkt, SSH1_TTY_OP_OSPEED);\r
6001         ssh_pkt_adduint32(pkt, ssh->ospeed);\r
6002         ssh_pkt_addbyte(pkt, SSH_TTY_OP_END);\r
6003         s_wrpkt(ssh, pkt);\r
6004         ssh->state = SSH_STATE_INTERMED;\r
6005         do {\r
6006             crReturnV;\r
6007         } while (!pktin);\r
6008         if (pktin->type != SSH1_SMSG_SUCCESS\r
6009             && pktin->type != SSH1_SMSG_FAILURE) {\r
6010             bombout(("Protocol confusion"));\r
6011             crStopV;\r
6012         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
6013             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
6014             ssh->editing = ssh->echoing = 1;\r
6015         } else {\r
6016             logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
6017                       ssh->ospeed, ssh->ispeed);\r
6018             ssh->got_pty = TRUE;\r
6019         }\r
6020     } else {\r
6021         ssh->editing = ssh->echoing = 1;\r
6022     }\r
6024     if (conf_get_int(ssh->conf, CONF_compression)) {\r
6025         send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);\r
6026         do {\r
6027             crReturnV;\r
6028         } while (!pktin);\r
6029         if (pktin->type != SSH1_SMSG_SUCCESS\r
6030             && pktin->type != SSH1_SMSG_FAILURE) {\r
6031             bombout(("Protocol confusion"));\r
6032             crStopV;\r
6033         } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
6034             c_write_str(ssh, "Server refused to compress\r\n");\r
6035         }\r
6036         logevent("Started compression");\r
6037         ssh->v1_compressing = TRUE;\r
6038         ssh->cs_comp_ctx = zlib_compress_init();\r
6039         logevent("Initialised zlib (RFC1950) compression");\r
6040         ssh->sc_comp_ctx = zlib_decompress_init();\r
6041         logevent("Initialised zlib (RFC1950) decompression");\r
6042     }\r
6044     /*\r
6045      * Start the shell or command.\r
6046      * \r
6047      * Special case: if the first-choice command is an SSH-2\r
6048      * subsystem (hence not usable here) and the second choice\r
6049      * exists, we fall straight back to that.\r
6050      */\r
6051     {\r
6052         char *cmd = conf_get_str(ssh->conf, CONF_remote_cmd);\r
6053         \r
6054         if (conf_get_int(ssh->conf, CONF_ssh_subsys) &&\r
6055             conf_get_str(ssh->conf, CONF_remote_cmd2)) {\r
6056             cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);\r
6057             ssh->fallback_cmd = TRUE;\r
6058         }\r
6059         if (*cmd)\r
6060             send_packet(ssh, SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);\r
6061         else\r
6062             send_packet(ssh, SSH1_CMSG_EXEC_SHELL, PKT_END);\r
6063         logevent("Started session");\r
6064     }\r
6066     ssh->state = SSH_STATE_SESSION;\r
6067     if (ssh->size_needed)\r
6068         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
6069     if (ssh->eof_needed)\r
6070         ssh_special(ssh, TS_EOF);\r
6072     if (ssh->ldisc)\r
6073         ldisc_echoedit_update(ssh->ldisc);  /* cause ldisc to notice changes */\r
6074     ssh->send_ok = 1;\r
6075     ssh->channels = newtree234(ssh_channelcmp);\r
6076     while (1) {\r
6078         /*\r
6079          * By this point, most incoming packets are already being\r
6080          * handled by the dispatch table, and we need only pay\r
6081          * attention to the unusual ones.\r
6082          */\r
6084         crReturnV;\r
6085         if (pktin) {\r
6086             if (pktin->type == SSH1_SMSG_SUCCESS) {\r
6087                 /* may be from EXEC_SHELL on some servers */\r
6088             } else if (pktin->type == SSH1_SMSG_FAILURE) {\r
6089                 /* may be from EXEC_SHELL on some servers\r
6090                  * if no pty is available or in other odd cases. Ignore */\r
6091             } else {\r
6092                 bombout(("Strange packet received: type %d", pktin->type));\r
6093                 crStopV;\r
6094             }\r
6095         } else {\r
6096             while (inlen > 0) {\r
6097                 int len = min(inlen, 512);\r
6098                 send_packet(ssh, SSH1_CMSG_STDIN_DATA,\r
6099                             PKT_INT, len, PKT_DATA, in, len,\r
6100                             PKT_END);\r
6101                 in += len;\r
6102                 inlen -= len;\r
6103             }\r
6104         }\r
6105     }\r
6107     crFinishV;\r
6110 /*\r
6111  * Handle the top-level SSH-2 protocol.\r
6112  */\r
6113 static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin)\r
6115     char *msg;\r
6116     int msglen;\r
6118     ssh_pkt_getstring(pktin, &msg, &msglen);\r
6119     logeventf(ssh, "Remote debug message: %.*s", msglen, NULLTOEMPTY(msg));\r
6122 static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
6124     /* log reason code in disconnect message */\r
6125     char *msg;\r
6126     int msglen;\r
6128     ssh_pkt_getstring(pktin, &msg, &msglen);\r
6129     bombout(("Server sent disconnect message:\n\"%.*s\"",\r
6130              msglen, NULLTOEMPTY(msg)));\r
6133 static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)\r
6135     /* Do nothing, because we're ignoring it! Duhh. */\r
6138 static void ssh1_protocol_setup(Ssh ssh)\r
6140     int i;\r
6142     /*\r
6143      * Most messages are handled by the coroutines.\r
6144      */\r
6145     for (i = 0; i < 256; i++)\r
6146         ssh->packet_dispatch[i] = NULL;\r
6148     /*\r
6149      * These special message types we install handlers for.\r
6150      */\r
6151     ssh->packet_dispatch[SSH1_MSG_DISCONNECT] = ssh1_msg_disconnect;\r
6152     ssh->packet_dispatch[SSH1_MSG_IGNORE] = ssh_msg_ignore;\r
6153     ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug;\r
6156 static void ssh1_protocol(Ssh ssh, const void *vin, int inlen,\r
6157                           struct Packet *pktin)\r
6159     const unsigned char *in = (const unsigned char *)vin;\r
6160     if (ssh->state == SSH_STATE_CLOSED)\r
6161         return;\r
6163     if (pktin && ssh->packet_dispatch[pktin->type]) {\r
6164         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
6165         return;\r
6166     }\r
6168     if (!ssh->protocol_initial_phase_done) {\r
6169         if (do_ssh1_login(ssh, in, inlen, pktin))\r
6170             ssh->protocol_initial_phase_done = TRUE;\r
6171         else\r
6172             return;\r
6173     }\r
6175     do_ssh1_connection(ssh, in, inlen, pktin);\r
6178 /*\r
6179  * Utility routines for decoding comma-separated strings in KEXINIT.\r
6180  */\r
6181 static int first_in_commasep_string(char const *needle, char const *haystack,\r
6182                                     int haylen)\r
6184     int needlen;\r
6185     if (!needle || !haystack)          /* protect against null pointers */\r
6186         return 0;\r
6187     needlen = strlen(needle);\r
6189     if (haylen >= needlen &&       /* haystack is long enough */\r
6190         !memcmp(needle, haystack, needlen) &&   /* initial match */\r
6191         (haylen == needlen || haystack[needlen] == ',')\r
6192         /* either , or EOS follows */\r
6193         )\r
6194         return 1;\r
6195     return 0;\r
6198 static int in_commasep_string(char const *needle, char const *haystack,\r
6199                               int haylen)\r
6201     char *p;\r
6203     if (!needle || !haystack)          /* protect against null pointers */\r
6204         return 0;\r
6205     /*\r
6206      * Is it at the start of the string?\r
6207      */\r
6208     if (first_in_commasep_string(needle, haystack, haylen))\r
6209         return 1;\r
6210     /*\r
6211      * If not, search for the next comma and resume after that.\r
6212      * If no comma found, terminate.\r
6213      */\r
6214     p = memchr(haystack, ',', haylen);\r
6215     if (!p) return 0;\r
6216     /* + 1 to skip over comma */\r
6217     return in_commasep_string(needle, p + 1, haylen - (p + 1 - haystack));\r
6220 /*\r
6221  * Add a value to the comma-separated string at the end of the packet.\r
6222  */\r
6223 static void ssh2_pkt_addstring_commasep(struct Packet *pkt, const char *data)\r
6225     if (pkt->length - pkt->savedpos > 0)\r
6226         ssh_pkt_addstring_str(pkt, ",");\r
6227     ssh_pkt_addstring_str(pkt, data);\r
6231 /*\r
6232  * SSH-2 key derivation (RFC 4253 section 7.2).\r
6233  */\r
6234 static unsigned char *ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H,\r
6235                                  char chr, int keylen)\r
6237     const struct ssh_hash *h = ssh->kex->hash;\r
6238     int keylen_padded;\r
6239     unsigned char *key;\r
6240     void *s, *s2;\r
6242     if (keylen == 0)\r
6243         return NULL;\r
6245     /* Round up to the next multiple of hash length. */\r
6246     keylen_padded = ((keylen + h->hlen - 1) / h->hlen) * h->hlen;\r
6248     key = snewn(keylen_padded, unsigned char);\r
6250     /* First hlen bytes. */\r
6251     s = h->init();\r
6252     if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
6253         hash_mpint(h, s, K);\r
6254     h->bytes(s, H, h->hlen);\r
6255     h->bytes(s, &chr, 1);\r
6256     h->bytes(s, ssh->v2_session_id, ssh->v2_session_id_len);\r
6257     h->final(s, key);\r
6259     /* Subsequent blocks of hlen bytes. */\r
6260     if (keylen_padded > h->hlen) {\r
6261         int offset;\r
6263         s = h->init();\r
6264         if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))\r
6265             hash_mpint(h, s, K);\r
6266         h->bytes(s, H, h->hlen);\r
6268         for (offset = h->hlen; offset < keylen_padded; offset += h->hlen) {\r
6269             h->bytes(s, key + offset - h->hlen, h->hlen);\r
6270             s2 = h->copy(s);\r
6271             h->final(s2, key + offset);\r
6272         }\r
6274         h->free(s);\r
6275     }\r
6277     /* Now clear any extra bytes of key material beyond the length\r
6278      * we're officially returning, because the caller won't know to\r
6279      * smemclr those. */\r
6280     if (keylen_padded > keylen)\r
6281         smemclr(key + keylen, keylen_padded - keylen);\r
6283     return key;\r
6286 /*\r
6287  * Structure for constructing KEXINIT algorithm lists.\r
6288  */\r
6289 #define MAXKEXLIST 16\r
6290 struct kexinit_algorithm {\r
6291     const char *name;\r
6292     union {\r
6293         struct {\r
6294             const struct ssh_kex *kex;\r
6295             int warn;\r
6296         } kex;\r
6297         struct {\r
6298             const struct ssh_signkey *hostkey;\r
6299             int warn;\r
6300         } hk;\r
6301         struct {\r
6302             const struct ssh2_cipher *cipher;\r
6303             int warn;\r
6304         } cipher;\r
6305         struct {\r
6306             const struct ssh_mac *mac;\r
6307             int etm;\r
6308         } mac;\r
6309         const struct ssh_compress *comp;\r
6310     } u;\r
6311 };\r
6313 /*\r
6314  * Find a slot in a KEXINIT algorithm list to use for a new algorithm.\r
6315  * If the algorithm is already in the list, return a pointer to its\r
6316  * entry, otherwise return an entry from the end of the list.\r
6317  * This assumes that every time a particular name is passed in, it\r
6318  * comes from the same string constant.  If this isn't true, this\r
6319  * function may need to be rewritten to use strcmp() instead.\r
6320  */\r
6321 static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm\r
6322                                                      *list, const char *name)\r
6324     int i;\r
6326     for (i = 0; i < MAXKEXLIST; i++)\r
6327         if (list[i].name == NULL || list[i].name == name) {\r
6328             list[i].name = name;\r
6329             return &list[i];\r
6330         }\r
6331     assert(!"No space in KEXINIT list");\r
6332     return NULL;\r
6335 /*\r
6336  * Handle the SSH-2 transport layer.\r
6337  */\r
6338 static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,\r
6339                              struct Packet *pktin)\r
6341     const unsigned char *in = (const unsigned char *)vin;\r
6342     enum kexlist {\r
6343         KEXLIST_KEX, KEXLIST_HOSTKEY, KEXLIST_CSCIPHER, KEXLIST_SCCIPHER,\r
6344         KEXLIST_CSMAC, KEXLIST_SCMAC, KEXLIST_CSCOMP, KEXLIST_SCCOMP,\r
6345         NKEXLIST\r
6346     };\r
6347     const char * kexlist_descr[NKEXLIST] = {\r
6348         "key exchange algorithm", "host key algorithm",\r
6349         "client-to-server cipher", "server-to-client cipher",\r
6350         "client-to-server MAC", "server-to-client MAC",\r
6351         "client-to-server compression method",\r
6352         "server-to-client compression method" };\r
6353     struct do_ssh2_transport_state {\r
6354         int crLine;\r
6355         int nbits, pbits, warn_kex, warn_hk, warn_cscipher, warn_sccipher;\r
6356         Bignum p, g, e, f, K;\r
6357         void *our_kexinit;\r
6358         int our_kexinitlen;\r
6359         int kex_init_value, kex_reply_value;\r
6360         const struct ssh_mac *const *maclist;\r
6361         int nmacs;\r
6362         const struct ssh2_cipher *cscipher_tobe;\r
6363         const struct ssh2_cipher *sccipher_tobe;\r
6364         const struct ssh_mac *csmac_tobe;\r
6365         const struct ssh_mac *scmac_tobe;\r
6366         int csmac_etm_tobe, scmac_etm_tobe;\r
6367         const struct ssh_compress *cscomp_tobe;\r
6368         const struct ssh_compress *sccomp_tobe;\r
6369         char *hostkeydata, *sigdata, *rsakeydata, *keystr, *fingerprint;\r
6370         int hostkeylen, siglen, rsakeylen;\r
6371         void *hkey;                    /* actual host key */\r
6372         void *rsakey;                  /* for RSA kex */\r
6373         void *eckey;                   /* for ECDH kex */\r
6374         unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN];\r
6375         int n_preferred_kex;\r
6376         const struct ssh_kexes *preferred_kex[KEX_MAX];\r
6377         int n_preferred_hk;\r
6378         int preferred_hk[HK_MAX];\r
6379         int n_preferred_ciphers;\r
6380         const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];\r
6381         const struct ssh_compress *preferred_comp;\r
6382         int userauth_succeeded;     /* for delayed compression */\r
6383         int pending_compression;\r
6384         int got_session_id, activated_authconn;\r
6385         struct Packet *pktout;\r
6386         int dlgret;\r
6387         int guessok;\r
6388         int ignorepkt;\r
6389         struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST];\r
6390     };\r
6391     crState(do_ssh2_transport_state);\r
6393     assert(!ssh->bare_connection);\r
6394     assert(ssh->version == 2);\r
6396     crBeginState;\r
6398     s->cscipher_tobe = s->sccipher_tobe = NULL;\r
6399     s->csmac_tobe = s->scmac_tobe = NULL;\r
6400     s->cscomp_tobe = s->sccomp_tobe = NULL;\r
6402     s->got_session_id = s->activated_authconn = FALSE;\r
6403     s->userauth_succeeded = FALSE;\r
6404     s->pending_compression = FALSE;\r
6406     /*\r
6407      * Be prepared to work around the buggy MAC problem.\r
6408      */\r
6409     if (ssh->remote_bugs & BUG_SSH2_HMAC)\r
6410         s->maclist = buggymacs, s->nmacs = lenof(buggymacs);\r
6411     else\r
6412         s->maclist = macs, s->nmacs = lenof(macs);\r
6414   begin_key_exchange:\r
6415     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
6416     {\r
6417         int i, j, k, warn;\r
6418         struct kexinit_algorithm *alg;\r
6420         /*\r
6421          * Set up the preferred key exchange. (NULL => warn below here)\r
6422          */\r
6423         s->n_preferred_kex = 0;\r
6424         for (i = 0; i < KEX_MAX; i++) {\r
6425             switch (conf_get_int_int(ssh->conf, CONF_ssh_kexlist, i)) {\r
6426               case KEX_DHGEX:\r
6427                 s->preferred_kex[s->n_preferred_kex++] =\r
6428                     &ssh_diffiehellman_gex;\r
6429                 break;\r
6430               case KEX_DHGROUP14:\r
6431                 s->preferred_kex[s->n_preferred_kex++] =\r
6432                     &ssh_diffiehellman_group14;\r
6433                 break;\r
6434               case KEX_DHGROUP1:\r
6435                 s->preferred_kex[s->n_preferred_kex++] =\r
6436                     &ssh_diffiehellman_group1;\r
6437                 break;\r
6438               case KEX_RSA:\r
6439                 s->preferred_kex[s->n_preferred_kex++] =\r
6440                     &ssh_rsa_kex;\r
6441                 break;\r
6442               case KEX_ECDH:\r
6443                 s->preferred_kex[s->n_preferred_kex++] =\r
6444                     &ssh_ecdh_kex;\r
6445                 break;\r
6446               case KEX_WARN:\r
6447                 /* Flag for later. Don't bother if it's the last in\r
6448                  * the list. */\r
6449                 if (i < KEX_MAX - 1) {\r
6450                     s->preferred_kex[s->n_preferred_kex++] = NULL;\r
6451                 }\r
6452                 break;\r
6453             }\r
6454         }\r
6456         /*\r
6457          * Set up the preferred host key types. These are just the ids\r
6458          * in the enum in putty.h, so 'warn below here' is indicated\r
6459          * by HK_WARN.\r
6460          */\r
6461         s->n_preferred_hk = 0;\r
6462         for (i = 0; i < HK_MAX; i++) {\r
6463             int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, i);\r
6464             /* As above, don't bother with HK_WARN if it's last in the\r
6465              * list */\r
6466             if (id != HK_WARN || i < HK_MAX - 1)\r
6467                 s->preferred_hk[s->n_preferred_hk++] = id;\r
6468         }\r
6470         /*\r
6471          * Set up the preferred ciphers. (NULL => warn below here)\r
6472          */\r
6473         s->n_preferred_ciphers = 0;\r
6474         for (i = 0; i < CIPHER_MAX; i++) {\r
6475             switch (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i)) {\r
6476               case CIPHER_BLOWFISH:\r
6477                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish;\r
6478                 break;\r
6479               case CIPHER_DES:\r
6480                 if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc)) {\r
6481                     s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des;\r
6482                 }\r
6483                 break;\r
6484               case CIPHER_3DES:\r
6485                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des;\r
6486                 break;\r
6487               case CIPHER_AES:\r
6488                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes;\r
6489                 break;\r
6490               case CIPHER_ARCFOUR:\r
6491                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour;\r
6492                 break;\r
6493               case CIPHER_CHACHA20:\r
6494                 s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_ccp;\r
6495                 break;\r
6496               case CIPHER_WARN:\r
6497                 /* Flag for later. Don't bother if it's the last in\r
6498                  * the list. */\r
6499                 if (i < CIPHER_MAX - 1) {\r
6500                     s->preferred_ciphers[s->n_preferred_ciphers++] = NULL;\r
6501                 }\r
6502                 break;\r
6503             }\r
6504         }\r
6506         /*\r
6507          * Set up preferred compression.\r
6508          */\r
6509         if (conf_get_int(ssh->conf, CONF_compression))\r
6510             s->preferred_comp = &ssh_zlib;\r
6511         else\r
6512             s->preferred_comp = &ssh_comp_none;\r
6514         /*\r
6515          * Enable queueing of outgoing auth- or connection-layer\r
6516          * packets while we are in the middle of a key exchange.\r
6517          */\r
6518         ssh->queueing = TRUE;\r
6520         /*\r
6521          * Flag that KEX is in progress.\r
6522          */\r
6523         ssh->kex_in_progress = TRUE;\r
6525         for (i = 0; i < NKEXLIST; i++)\r
6526             for (j = 0; j < MAXKEXLIST; j++)\r
6527                 s->kexlists[i][j].name = NULL;\r
6528         /* List key exchange algorithms. */\r
6529         warn = FALSE;\r
6530         for (i = 0; i < s->n_preferred_kex; i++) {\r
6531             const struct ssh_kexes *k = s->preferred_kex[i];\r
6532             if (!k) warn = TRUE;\r
6533             else for (j = 0; j < k->nkexes; j++) {\r
6534                 alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_KEX],\r
6535                                           k->list[j]->name);\r
6536                 alg->u.kex.kex = k->list[j];\r
6537                 alg->u.kex.warn = warn;\r
6538             }\r
6539         }\r
6540         /* List server host key algorithms. */\r
6541         if (!s->got_session_id) {\r
6542             /*\r
6543              * In the first key exchange, we list all the algorithms\r
6544              * we're prepared to cope with, but prefer those algorithms\r
6545              * for which we have a host key for this host.\r
6546              *\r
6547              * If the host key algorithm is below the warning\r
6548              * threshold, we warn even if we did already have a key\r
6549              * for it, on the basis that if the user has just\r
6550              * reconfigured that host key type to be warned about,\r
6551              * they surely _do_ want to be alerted that a server\r
6552              * they're actually connecting to is using it.\r
6553              */\r
6554             warn = FALSE;\r
6555             for (i = 0; i < s->n_preferred_hk; i++) {\r
6556                 if (s->preferred_hk[i] == HK_WARN)\r
6557                     warn = TRUE;\r
6558                 for (j = 0; j < lenof(hostkey_algs); j++) {\r
6559                     if (hostkey_algs[j].id != s->preferred_hk[i])\r
6560                         continue;\r
6561                     if (have_ssh_host_key(ssh->savedhost, ssh->savedport,\r
6562                                           hostkey_algs[j].alg->keytype)) {\r
6563                         alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY],\r
6564                                                   hostkey_algs[j].alg->name);\r
6565                         alg->u.hk.hostkey = hostkey_algs[j].alg;\r
6566                         alg->u.hk.warn = warn;\r
6567                     }\r
6568                 }\r
6569             }\r
6570             warn = FALSE;\r
6571             for (i = 0; i < s->n_preferred_hk; i++) {\r
6572                 if (s->preferred_hk[i] == HK_WARN)\r
6573                     warn = TRUE;\r
6574                 for (j = 0; j < lenof(hostkey_algs); j++) {\r
6575                     if (hostkey_algs[j].id != s->preferred_hk[i])\r
6576                         continue;\r
6577                     alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY],\r
6578                                               hostkey_algs[j].alg->name);\r
6579                     alg->u.hk.hostkey = hostkey_algs[j].alg;\r
6580                     alg->u.hk.warn = warn;\r
6581                 }\r
6582             }\r
6583         } else {\r
6584             /*\r
6585              * In subsequent key exchanges, we list only the kex\r
6586              * algorithm that was selected in the first key exchange,\r
6587              * so that we keep getting the same host key and hence\r
6588              * don't have to interrupt the user's session to ask for\r
6589              * reverification.\r
6590              */\r
6591             assert(ssh->kex);\r
6592             alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY],\r
6593                                       ssh->hostkey->name);\r
6594             alg->u.hk.hostkey = ssh->hostkey;\r
6595             alg->u.hk.warn = FALSE;\r
6596         }\r
6597         /* List encryption algorithms (client->server then server->client). */\r
6598         for (k = KEXLIST_CSCIPHER; k <= KEXLIST_SCCIPHER; k++) {\r
6599             warn = FALSE;\r
6600 #ifdef FUZZING\r
6601             alg = ssh2_kexinit_addalg(s->kexlists[k], "none");\r
6602             alg->u.cipher.cipher = NULL;\r
6603             alg->u.cipher.warn = warn;\r
6604 #endif /* FUZZING */\r
6605             for (i = 0; i < s->n_preferred_ciphers; i++) {\r
6606                 const struct ssh2_ciphers *c = s->preferred_ciphers[i];\r
6607                 if (!c) warn = TRUE;\r
6608                 else for (j = 0; j < c->nciphers; j++) {\r
6609                     alg = ssh2_kexinit_addalg(s->kexlists[k],\r
6610                                               c->list[j]->name);\r
6611                     alg->u.cipher.cipher = c->list[j];\r
6612                     alg->u.cipher.warn = warn;\r
6613                 }\r
6614             }\r
6615         }\r
6616         /* List MAC algorithms (client->server then server->client). */\r
6617         for (j = KEXLIST_CSMAC; j <= KEXLIST_SCMAC; j++) {\r
6618 #ifdef FUZZING\r
6619             alg = ssh2_kexinit_addalg(s->kexlists[j], "none");\r
6620             alg->u.mac.mac = NULL;\r
6621             alg->u.mac.etm = FALSE;\r
6622 #endif /* FUZZING */\r
6623             for (i = 0; i < s->nmacs; i++) {\r
6624                 alg = ssh2_kexinit_addalg(s->kexlists[j], s->maclist[i]->name);\r
6625                 alg->u.mac.mac = s->maclist[i];\r
6626                 alg->u.mac.etm = FALSE;\r
6627             }\r
6628             for (i = 0; i < s->nmacs; i++)\r
6629                 /* For each MAC, there may also be an ETM version,\r
6630                  * which we list second. */\r
6631                 if (s->maclist[i]->etm_name) {\r
6632                     alg = ssh2_kexinit_addalg(s->kexlists[j],\r
6633                                               s->maclist[i]->etm_name);\r
6634                     alg->u.mac.mac = s->maclist[i];\r
6635                     alg->u.mac.etm = TRUE;\r
6636                 }\r
6637         }\r
6638         /* List client->server compression algorithms,\r
6639          * then server->client compression algorithms. (We use the\r
6640          * same set twice.) */\r
6641         for (j = KEXLIST_CSCOMP; j <= KEXLIST_SCCOMP; j++) {\r
6642             assert(lenof(compressions) > 1);\r
6643             /* Prefer non-delayed versions */\r
6644             alg = ssh2_kexinit_addalg(s->kexlists[j], s->preferred_comp->name);\r
6645             alg->u.comp = s->preferred_comp;\r
6646             /* We don't even list delayed versions of algorithms until\r
6647              * they're allowed to be used, to avoid a race. See the end of\r
6648              * this function. */\r
6649             if (s->userauth_succeeded && s->preferred_comp->delayed_name) {\r
6650                 alg = ssh2_kexinit_addalg(s->kexlists[j],\r
6651                                           s->preferred_comp->delayed_name);\r
6652                 alg->u.comp = s->preferred_comp;\r
6653             }\r
6654             for (i = 0; i < lenof(compressions); i++) {\r
6655                 const struct ssh_compress *c = compressions[i];\r
6656                 alg = ssh2_kexinit_addalg(s->kexlists[j], c->name);\r
6657                 alg->u.comp = c;\r
6658                 if (s->userauth_succeeded && c->delayed_name) {\r
6659                     alg = ssh2_kexinit_addalg(s->kexlists[j], c->delayed_name);\r
6660                     alg->u.comp = c;\r
6661                 }\r
6662             }\r
6663         }\r
6664         /*\r
6665          * Construct and send our key exchange packet.\r
6666          */\r
6667         s->pktout = ssh2_pkt_init(SSH2_MSG_KEXINIT);\r
6668         for (i = 0; i < 16; i++)\r
6669             ssh2_pkt_addbyte(s->pktout, (unsigned char) random_byte());\r
6670         for (i = 0; i < NKEXLIST; i++) {\r
6671             ssh2_pkt_addstring_start(s->pktout);\r
6672             for (j = 0; j < MAXKEXLIST; j++) {\r
6673                 if (s->kexlists[i][j].name == NULL) break;\r
6674                 ssh2_pkt_addstring_commasep(s->pktout, s->kexlists[i][j].name);\r
6675             }\r
6676         }\r
6677         /* List client->server languages. Empty list. */\r
6678         ssh2_pkt_addstring_start(s->pktout);\r
6679         /* List server->client languages. Empty list. */\r
6680         ssh2_pkt_addstring_start(s->pktout);\r
6681         /* First KEX packet does _not_ follow, because we're not that brave. */\r
6682         ssh2_pkt_addbool(s->pktout, FALSE);\r
6683         /* Reserved. */\r
6684         ssh2_pkt_adduint32(s->pktout, 0);\r
6685     }\r
6687     s->our_kexinitlen = s->pktout->length - 5;\r
6688     s->our_kexinit = snewn(s->our_kexinitlen, unsigned char);\r
6689     memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); \r
6691     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
6693     if (!pktin)\r
6694         crWaitUntilV(pktin);\r
6696     /*\r
6697      * Now examine the other side's KEXINIT to see what we're up\r
6698      * to.\r
6699      */\r
6700     {\r
6701         char *str;\r
6702         int i, j, len;\r
6704         if (pktin->type != SSH2_MSG_KEXINIT) {\r
6705             bombout(("expected key exchange packet from server"));\r
6706             crStopV;\r
6707         }\r
6708         ssh->kex = NULL;\r
6709         ssh->hostkey = NULL;\r
6710         s->cscipher_tobe = NULL;\r
6711         s->sccipher_tobe = NULL;\r
6712         s->csmac_tobe = NULL;\r
6713         s->scmac_tobe = NULL;\r
6714         s->cscomp_tobe = NULL;\r
6715         s->sccomp_tobe = NULL;\r
6716         s->warn_kex = s->warn_hk = FALSE;\r
6717         s->warn_cscipher = s->warn_sccipher = FALSE;\r
6719         pktin->savedpos += 16;          /* skip garbage cookie */\r
6721         s->guessok = FALSE;\r
6722         for (i = 0; i < NKEXLIST; i++) {\r
6723             ssh_pkt_getstring(pktin, &str, &len);\r
6724             if (!str) {\r
6725                 bombout(("KEXINIT packet was incomplete"));\r
6726                 crStopV;\r
6727             }\r
6729             /* If we've already selected a cipher which requires a\r
6730              * particular MAC, then just select that, and don't even\r
6731              * bother looking through the server's KEXINIT string for\r
6732              * MACs. */\r
6733             if (i == KEXLIST_CSMAC && s->cscipher_tobe &&\r
6734                 s->cscipher_tobe->required_mac) {\r
6735                 s->csmac_tobe = s->cscipher_tobe->required_mac;\r
6736                 s->csmac_etm_tobe = !!(s->csmac_tobe->etm_name);\r
6737                 goto matched;\r
6738             }\r
6739             if (i == KEXLIST_SCMAC && s->sccipher_tobe &&\r
6740                 s->sccipher_tobe->required_mac) {\r
6741                 s->scmac_tobe = s->sccipher_tobe->required_mac;\r
6742                 s->scmac_etm_tobe = !!(s->scmac_tobe->etm_name);\r
6743                 goto matched;\r
6744             }\r
6746             for (j = 0; j < MAXKEXLIST; j++) {\r
6747                 struct kexinit_algorithm *alg = &s->kexlists[i][j];\r
6748                 if (alg->name == NULL) break;\r
6749                 if (in_commasep_string(alg->name, str, len)) {\r
6750                     /* We've found a matching algorithm. */\r
6751                     if (i == KEXLIST_KEX || i == KEXLIST_HOSTKEY) {\r
6752                         /* Check if we might need to ignore first kex pkt */\r
6753                         if (j != 0 ||\r
6754                             !first_in_commasep_string(alg->name, str, len))\r
6755                             s->guessok = FALSE;\r
6756                     }\r
6757                     if (i == KEXLIST_KEX) {\r
6758                         ssh->kex = alg->u.kex.kex;\r
6759                         s->warn_kex = alg->u.kex.warn;\r
6760                     } else if (i == KEXLIST_HOSTKEY) {\r
6761                         ssh->hostkey = alg->u.hk.hostkey;\r
6762                         s->warn_hk = alg->u.hk.warn;\r
6763                     } else if (i == KEXLIST_CSCIPHER) {\r
6764                         s->cscipher_tobe = alg->u.cipher.cipher;\r
6765                         s->warn_cscipher = alg->u.cipher.warn;\r
6766                     } else if (i == KEXLIST_SCCIPHER) {\r
6767                         s->sccipher_tobe = alg->u.cipher.cipher;\r
6768                         s->warn_sccipher = alg->u.cipher.warn;\r
6769                     } else if (i == KEXLIST_CSMAC) {\r
6770                         s->csmac_tobe = alg->u.mac.mac;\r
6771                         s->csmac_etm_tobe = alg->u.mac.etm;\r
6772                     } else if (i == KEXLIST_SCMAC) {\r
6773                         s->scmac_tobe = alg->u.mac.mac;\r
6774                         s->scmac_etm_tobe = alg->u.mac.etm;\r
6775                     } else if (i == KEXLIST_CSCOMP) {\r
6776                         s->cscomp_tobe = alg->u.comp;\r
6777                     } else if (i == KEXLIST_SCCOMP) {\r
6778                         s->sccomp_tobe = alg->u.comp;\r
6779                     }\r
6780                     goto matched;\r
6781                 }\r
6782                 if ((i == KEXLIST_CSCOMP || i == KEXLIST_SCCOMP) &&\r
6783                     in_commasep_string(alg->u.comp->delayed_name, str, len))\r
6784                     s->pending_compression = TRUE;  /* try this later */\r
6785             }\r
6786             bombout(("Couldn't agree a %s (available: %.*s)",\r
6787                      kexlist_descr[i], len, str));\r
6788             crStopV;\r
6789           matched:;\r
6791             if (i == KEXLIST_HOSTKEY) {\r
6792                 int j;\r
6794                 /*\r
6795                  * In addition to deciding which host key we're\r
6796                  * actually going to use, we should make a list of the\r
6797                  * host keys offered by the server which we _don't_\r
6798                  * have cached. These will be offered as cross-\r
6799                  * certification options by ssh_get_specials.\r
6800                  *\r
6801                  * We also count the key we're currently using for KEX\r
6802                  * as one we've already got, because by the time this\r
6803                  * menu becomes visible, it will be.\r
6804                  */\r
6805                 ssh->n_uncert_hostkeys = 0;\r
6807                 for (j = 0; j < lenof(hostkey_algs); j++) {\r
6808                     if (hostkey_algs[j].alg != ssh->hostkey &&\r
6809                         in_commasep_string(hostkey_algs[j].alg->name,\r
6810                                            str, len) &&\r
6811                         !have_ssh_host_key(ssh->savedhost, ssh->savedport,\r
6812                                            hostkey_algs[j].alg->keytype)) {\r
6813                         ssh->uncert_hostkeys[ssh->n_uncert_hostkeys++] = j;\r
6814                     }\r
6815                 }\r
6816             }\r
6817         }\r
6819         if (s->pending_compression) {\r
6820             logevent("Server supports delayed compression; "\r
6821                      "will try this later");\r
6822         }\r
6823         ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */\r
6824         ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */\r
6825         s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok;\r
6827         ssh->exhash = ssh->kex->hash->init();\r
6828         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c));\r
6829         hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s));\r
6830         hash_string(ssh->kex->hash, ssh->exhash,\r
6831             s->our_kexinit, s->our_kexinitlen);\r
6832         sfree(s->our_kexinit);\r
6833         /* Include the type byte in the hash of server's KEXINIT */\r
6834         hash_string(ssh->kex->hash, ssh->exhash,\r
6835                     pktin->body - 1, pktin->length + 1);\r
6837         if (s->warn_kex) {\r
6838             ssh_set_frozen(ssh, 1);\r
6839             s->dlgret = askalg(ssh->frontend, "key-exchange algorithm",\r
6840                                ssh->kex->name,\r
6841                                ssh_dialog_callback, ssh);\r
6842             if (s->dlgret < 0) {\r
6843                 do {\r
6844                     crReturnV;\r
6845                     if (pktin) {\r
6846                         bombout(("Unexpected data from server while"\r
6847                                  " waiting for user response"));\r
6848                         crStopV;\r
6849                     }\r
6850                 } while (pktin || inlen > 0);\r
6851                 s->dlgret = ssh->user_response;\r
6852             }\r
6853             ssh_set_frozen(ssh, 0);\r
6854             if (s->dlgret == 0) {\r
6855                 ssh_disconnect(ssh, "User aborted at kex warning", NULL,\r
6856                                0, TRUE);\r
6857                 crStopV;\r
6858             }\r
6859         }\r
6861         if (s->warn_hk) {\r
6862             int j, k;\r
6863             char *betteralgs;\r
6865             ssh_set_frozen(ssh, 1);\r
6867             /*\r
6868              * Change warning box wording depending on why we chose a\r
6869              * warning-level host key algorithm. If it's because\r
6870              * that's all we have *cached*, use the askhk mechanism,\r
6871              * and list the host keys we could usefully cross-certify.\r
6872              * Otherwise, use askalg for the standard wording.\r
6873              */\r
6874             betteralgs = NULL;\r
6875             for (j = 0; j < ssh->n_uncert_hostkeys; j++) {\r
6876                 const struct ssh_signkey_with_user_pref_id *hktype =\r
6877                     &hostkey_algs[ssh->uncert_hostkeys[j]];\r
6878                 int better = FALSE;\r
6879                 for (k = 0; k < HK_MAX; k++) {\r
6880                     int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, k);\r
6881                     if (id == HK_WARN) {\r
6882                         break;\r
6883                     } else if (id == hktype->id) {\r
6884                         better = TRUE;\r
6885                         break;\r
6886                     }\r
6887                 }\r
6888                 if (better) {\r
6889                     if (betteralgs) {\r
6890                         char *old_ba = betteralgs;\r
6891                         betteralgs = dupcat(betteralgs, ",",\r
6892                                             hktype->alg->name,\r
6893                                             (const char *)NULL);\r
6894                         sfree(old_ba);\r
6895                     } else {\r
6896                         betteralgs = dupstr(hktype->alg->name);\r
6897                     }\r
6898                 }\r
6899             }\r
6900             if (betteralgs) {\r
6901                 s->dlgret = askhk(ssh->frontend, ssh->hostkey->name,\r
6902                                   betteralgs, ssh_dialog_callback, ssh);\r
6903                 sfree(betteralgs);\r
6904             } else {\r
6905                 s->dlgret = askalg(ssh->frontend, "host key type",\r
6906                                    ssh->hostkey->name,\r
6907                                    ssh_dialog_callback, ssh);\r
6908             }\r
6909             if (s->dlgret < 0) {\r
6910                 do {\r
6911                     crReturnV;\r
6912                     if (pktin) {\r
6913                         bombout(("Unexpected data from server while"\r
6914                                  " waiting for user response"));\r
6915                         crStopV;\r
6916                     }\r
6917                 } while (pktin || inlen > 0);\r
6918                 s->dlgret = ssh->user_response;\r
6919             }\r
6920             ssh_set_frozen(ssh, 0);\r
6921             if (s->dlgret == 0) {\r
6922                 ssh_disconnect(ssh, "User aborted at host key warning", NULL,\r
6923                                0, TRUE);\r
6924                 crStopV;\r
6925             }\r
6926         }\r
6928         if (s->warn_cscipher) {\r
6929             ssh_set_frozen(ssh, 1);\r
6930             s->dlgret = askalg(ssh->frontend,\r
6931                                "client-to-server cipher",\r
6932                                s->cscipher_tobe->name,\r
6933                                ssh_dialog_callback, ssh);\r
6934             if (s->dlgret < 0) {\r
6935                 do {\r
6936                     crReturnV;\r
6937                     if (pktin) {\r
6938                         bombout(("Unexpected data from server while"\r
6939                                  " waiting for user response"));\r
6940                         crStopV;\r
6941                     }\r
6942                 } while (pktin || inlen > 0);\r
6943                 s->dlgret = ssh->user_response;\r
6944             }\r
6945             ssh_set_frozen(ssh, 0);\r
6946             if (s->dlgret == 0) {\r
6947                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
6948                                0, TRUE);\r
6949                 crStopV;\r
6950             }\r
6951         }\r
6953         if (s->warn_sccipher) {\r
6954             ssh_set_frozen(ssh, 1);\r
6955             s->dlgret = askalg(ssh->frontend,\r
6956                                "server-to-client cipher",\r
6957                                s->sccipher_tobe->name,\r
6958                                ssh_dialog_callback, ssh);\r
6959             if (s->dlgret < 0) {\r
6960                 do {\r
6961                     crReturnV;\r
6962                     if (pktin) {\r
6963                         bombout(("Unexpected data from server while"\r
6964                                  " waiting for user response"));\r
6965                         crStopV;\r
6966                     }\r
6967                 } while (pktin || inlen > 0);\r
6968                 s->dlgret = ssh->user_response;\r
6969             }\r
6970             ssh_set_frozen(ssh, 0);\r
6971             if (s->dlgret == 0) {\r
6972                 ssh_disconnect(ssh, "User aborted at cipher warning", NULL,\r
6973                                0, TRUE);\r
6974                 crStopV;\r
6975             }\r
6976         }\r
6978         if (s->ignorepkt) /* first_kex_packet_follows */\r
6979             crWaitUntilV(pktin);                /* Ignore packet */\r
6980     }\r
6982     if (ssh->kex->main_type == KEXTYPE_DH) {\r
6983         /*\r
6984          * Work out the number of bits of key we will need from the\r
6985          * key exchange. We start with the maximum key length of\r
6986          * either cipher...\r
6987          */\r
6988         {\r
6989             int csbits, scbits;\r
6991             csbits = s->cscipher_tobe ? s->cscipher_tobe->real_keybits : 0;\r
6992             scbits = s->sccipher_tobe ? s->sccipher_tobe->real_keybits : 0;\r
6993             s->nbits = (csbits > scbits ? csbits : scbits);\r
6994         }\r
6995         /* The keys only have hlen-bit entropy, since they're based on\r
6996          * a hash. So cap the key size at hlen bits. */\r
6997         if (s->nbits > ssh->kex->hash->hlen * 8)\r
6998             s->nbits = ssh->kex->hash->hlen * 8;\r
7000         /*\r
7001          * If we're doing Diffie-Hellman group exchange, start by\r
7002          * requesting a group.\r
7003          */\r
7004         if (dh_is_gex(ssh->kex)) {\r
7005             logevent("Doing Diffie-Hellman group exchange");\r
7006             ssh->pkt_kctx = SSH2_PKTCTX_DHGEX;\r
7007             /*\r
7008              * Work out how big a DH group we will need to allow that\r
7009              * much data.\r
7010              */\r
7011             s->pbits = 512 << ((s->nbits - 1) / 64);\r
7012             if (s->pbits < DH_MIN_SIZE)\r
7013                 s->pbits = DH_MIN_SIZE;\r
7014             if (s->pbits > DH_MAX_SIZE)\r
7015                 s->pbits = DH_MAX_SIZE;\r
7016             if ((ssh->remote_bugs & BUG_SSH2_OLDGEX)) {\r
7017                 s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);\r
7018                 ssh2_pkt_adduint32(s->pktout, s->pbits);\r
7019             } else {\r
7020                 s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);\r
7021                 ssh2_pkt_adduint32(s->pktout, DH_MIN_SIZE);\r
7022                 ssh2_pkt_adduint32(s->pktout, s->pbits);\r
7023                 ssh2_pkt_adduint32(s->pktout, DH_MAX_SIZE);\r
7024             }\r
7025             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
7027             crWaitUntilV(pktin);\r
7028             if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) {\r
7029                 bombout(("expected key exchange group packet from server"));\r
7030                 crStopV;\r
7031             }\r
7032             s->p = ssh2_pkt_getmp(pktin);\r
7033             s->g = ssh2_pkt_getmp(pktin);\r
7034             if (!s->p || !s->g) {\r
7035                 bombout(("unable to read mp-ints from incoming group packet"));\r
7036                 crStopV;\r
7037             }\r
7038             ssh->kex_ctx = dh_setup_gex(s->p, s->g);\r
7039             s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;\r
7040             s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;\r
7041         } else {\r
7042             ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP;\r
7043             ssh->kex_ctx = dh_setup_group(ssh->kex);\r
7044             s->kex_init_value = SSH2_MSG_KEXDH_INIT;\r
7045             s->kex_reply_value = SSH2_MSG_KEXDH_REPLY;\r
7046             logeventf(ssh, "Using Diffie-Hellman with standard group \"%s\"",\r
7047                       ssh->kex->groupname);\r
7048         }\r
7050         logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s",\r
7051                   ssh->kex->hash->text_name);\r
7052         /*\r
7053          * Now generate and send e for Diffie-Hellman.\r
7054          */\r
7055         set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */\r
7056         s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2);\r
7057         s->pktout = ssh2_pkt_init(s->kex_init_value);\r
7058         ssh2_pkt_addmp(s->pktout, s->e);\r
7059         ssh2_pkt_send_noqueue(ssh, s->pktout);\r
7061         set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */\r
7062         crWaitUntilV(pktin);\r
7063         if (pktin->type != s->kex_reply_value) {\r
7064             bombout(("expected key exchange reply packet from server"));\r
7065             crStopV;\r
7066         }\r
7067         set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */\r
7068         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
7069         if (!s->hostkeydata) {\r
7070             bombout(("unable to parse key exchange reply packet"));\r
7071             crStopV;\r
7072         }\r
7073         s->hkey = ssh->hostkey->newkey(ssh->hostkey,\r
7074                                        s->hostkeydata, s->hostkeylen);\r
7075         s->f = ssh2_pkt_getmp(pktin);\r
7076         if (!s->f) {\r
7077             bombout(("unable to parse key exchange reply packet"));\r
7078             crStopV;\r
7079         }\r
7080         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
7081         if (!s->sigdata) {\r
7082             bombout(("unable to parse key exchange reply packet"));\r
7083             crStopV;\r
7084         }\r
7086         {\r
7087             const char *err = dh_validate_f(ssh->kex_ctx, s->f);\r
7088             if (err) {\r
7089                 bombout(("key exchange reply failed validation: %s", err));\r
7090                 crStopV;\r
7091             }\r
7092         }\r
7093         s->K = dh_find_K(ssh->kex_ctx, s->f);\r
7095         /* We assume everything from now on will be quick, and it might\r
7096          * involve user interaction. */\r
7097         set_busy_status(ssh->frontend, BUSY_NOT);\r
7099         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);\r
7100         if (dh_is_gex(ssh->kex)) {\r
7101             if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))\r
7102                 hash_uint32(ssh->kex->hash, ssh->exhash, DH_MIN_SIZE);\r
7103             hash_uint32(ssh->kex->hash, ssh->exhash, s->pbits);\r
7104             if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))\r
7105                 hash_uint32(ssh->kex->hash, ssh->exhash, DH_MAX_SIZE);\r
7106             hash_mpint(ssh->kex->hash, ssh->exhash, s->p);\r
7107             hash_mpint(ssh->kex->hash, ssh->exhash, s->g);\r
7108         }\r
7109         hash_mpint(ssh->kex->hash, ssh->exhash, s->e);\r
7110         hash_mpint(ssh->kex->hash, ssh->exhash, s->f);\r
7112         dh_cleanup(ssh->kex_ctx);\r
7113         freebn(s->f);\r
7114         if (dh_is_gex(ssh->kex)) {\r
7115             freebn(s->g);\r
7116             freebn(s->p);\r
7117         }\r
7118     } else if (ssh->kex->main_type == KEXTYPE_ECDH) {\r
7120         logeventf(ssh, "Doing ECDH key exchange with curve %s and hash %s",\r
7121                   ssh_ecdhkex_curve_textname(ssh->kex),\r
7122                   ssh->kex->hash->text_name);\r
7123         ssh->pkt_kctx = SSH2_PKTCTX_ECDHKEX;\r
7125         s->eckey = ssh_ecdhkex_newkey(ssh->kex);\r
7126         if (!s->eckey) {\r
7127             bombout(("Unable to generate key for ECDH"));\r
7128             crStopV;\r
7129         }\r
7131         {\r
7132             char *publicPoint;\r
7133             int publicPointLength;\r
7134             publicPoint = ssh_ecdhkex_getpublic(s->eckey, &publicPointLength);\r
7135             if (!publicPoint) {\r
7136                 ssh_ecdhkex_freekey(s->eckey);\r
7137                 bombout(("Unable to encode public key for ECDH"));\r
7138                 crStopV;\r
7139             }\r
7140             s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_ECDH_INIT);\r
7141             ssh2_pkt_addstring_start(s->pktout);\r
7142             ssh2_pkt_addstring_data(s->pktout, publicPoint, publicPointLength);\r
7143             sfree(publicPoint);\r
7144         }\r
7146         ssh2_pkt_send_noqueue(ssh, s->pktout);\r
7148         crWaitUntilV(pktin);\r
7149         if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) {\r
7150             ssh_ecdhkex_freekey(s->eckey);\r
7151             bombout(("expected ECDH reply packet from server"));\r
7152             crStopV;\r
7153         }\r
7155         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
7156         if (!s->hostkeydata) {\r
7157             bombout(("unable to parse ECDH reply packet"));\r
7158             crStopV;\r
7159         }\r
7160         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);\r
7161         s->hkey = ssh->hostkey->newkey(ssh->hostkey,\r
7162                                        s->hostkeydata, s->hostkeylen);\r
7164         {\r
7165             char *publicPoint;\r
7166             int publicPointLength;\r
7167             publicPoint = ssh_ecdhkex_getpublic(s->eckey, &publicPointLength);\r
7168             if (!publicPoint) {\r
7169                 ssh_ecdhkex_freekey(s->eckey);\r
7170                 bombout(("Unable to encode public key for ECDH hash"));\r
7171                 crStopV;\r
7172             }\r
7173             hash_string(ssh->kex->hash, ssh->exhash,\r
7174                         publicPoint, publicPointLength);\r
7175             sfree(publicPoint);\r
7176         }\r
7178         {\r
7179             char *keydata;\r
7180             int keylen;\r
7181             ssh_pkt_getstring(pktin, &keydata, &keylen);\r
7182             if (!keydata) {\r
7183                 bombout(("unable to parse ECDH reply packet"));\r
7184                 crStopV;\r
7185             }\r
7186             hash_string(ssh->kex->hash, ssh->exhash, keydata, keylen);\r
7187             s->K = ssh_ecdhkex_getkey(s->eckey, keydata, keylen);\r
7188             if (!s->K) {\r
7189                 ssh_ecdhkex_freekey(s->eckey);\r
7190                 bombout(("point received in ECDH was not valid"));\r
7191                 crStopV;\r
7192             }\r
7193         }\r
7195         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
7196         if (!s->sigdata) {\r
7197             bombout(("unable to parse key exchange reply packet"));\r
7198             crStopV;\r
7199         }\r
7201         ssh_ecdhkex_freekey(s->eckey);\r
7202     } else {\r
7203         logeventf(ssh, "Doing RSA key exchange with hash %s",\r
7204                   ssh->kex->hash->text_name);\r
7205         ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX;\r
7206         /*\r
7207          * RSA key exchange. First expect a KEXRSA_PUBKEY packet\r
7208          * from the server.\r
7209          */\r
7210         crWaitUntilV(pktin);\r
7211         if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) {\r
7212             bombout(("expected RSA public key packet from server"));\r
7213             crStopV;\r
7214         }\r
7216         ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);\r
7217         if (!s->hostkeydata) {\r
7218             bombout(("unable to parse RSA public key packet"));\r
7219             crStopV;\r
7220         }\r
7221         hash_string(ssh->kex->hash, ssh->exhash,\r
7222                     s->hostkeydata, s->hostkeylen);\r
7223         s->hkey = ssh->hostkey->newkey(ssh->hostkey,\r
7224                                        s->hostkeydata, s->hostkeylen);\r
7226         {\r
7227             char *keydata;\r
7228             ssh_pkt_getstring(pktin, &keydata, &s->rsakeylen);\r
7229             if (!keydata) {\r
7230                 bombout(("unable to parse RSA public key packet"));\r
7231                 crStopV;\r
7232             }\r
7233             s->rsakeydata = snewn(s->rsakeylen, char);\r
7234             memcpy(s->rsakeydata, keydata, s->rsakeylen);\r
7235         }\r
7237         s->rsakey = ssh_rsakex_newkey(s->rsakeydata, s->rsakeylen);\r
7238         if (!s->rsakey) {\r
7239             sfree(s->rsakeydata);\r
7240             bombout(("unable to parse RSA public key from server"));\r
7241             crStopV;\r
7242         }\r
7244         hash_string(ssh->kex->hash, ssh->exhash, s->rsakeydata, s->rsakeylen);\r
7246         /*\r
7247          * Next, set up a shared secret K, of precisely KLEN -\r
7248          * 2*HLEN - 49 bits, where KLEN is the bit length of the\r
7249          * RSA key modulus and HLEN is the bit length of the hash\r
7250          * we're using.\r
7251          */\r
7252         {\r
7253             int klen = ssh_rsakex_klen(s->rsakey);\r
7254             int nbits = klen - (2*ssh->kex->hash->hlen*8 + 49);\r
7255             int i, byte = 0;\r
7256             unsigned char *kstr1, *kstr2, *outstr;\r
7257             int kstr1len, kstr2len, outstrlen;\r
7259             s->K = bn_power_2(nbits - 1);\r
7261             for (i = 0; i < nbits; i++) {\r
7262                 if ((i & 7) == 0) {\r
7263                     byte = random_byte();\r
7264                 }\r
7265                 bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1);\r
7266             }\r
7268             /*\r
7269              * Encode this as an mpint.\r
7270              */\r
7271             kstr1 = ssh2_mpint_fmt(s->K, &kstr1len);\r
7272             kstr2 = snewn(kstr2len = 4 + kstr1len, unsigned char);\r
7273             PUT_32BIT(kstr2, kstr1len);\r
7274             memcpy(kstr2 + 4, kstr1, kstr1len);\r
7276             /*\r
7277              * Encrypt it with the given RSA key.\r
7278              */\r
7279             outstrlen = (klen + 7) / 8;\r
7280             outstr = snewn(outstrlen, unsigned char);\r
7281             ssh_rsakex_encrypt(ssh->kex->hash, kstr2, kstr2len,\r
7282                                outstr, outstrlen, s->rsakey);\r
7284             /*\r
7285              * And send it off in a return packet.\r
7286              */\r
7287             s->pktout = ssh2_pkt_init(SSH2_MSG_KEXRSA_SECRET);\r
7288             ssh2_pkt_addstring_start(s->pktout);\r
7289             ssh2_pkt_addstring_data(s->pktout, (char *)outstr, outstrlen);\r
7290             ssh2_pkt_send_noqueue(ssh, s->pktout);\r
7292             hash_string(ssh->kex->hash, ssh->exhash, outstr, outstrlen);\r
7294             sfree(kstr2);\r
7295             sfree(kstr1);\r
7296             sfree(outstr);\r
7297         }\r
7299         ssh_rsakex_freekey(s->rsakey);\r
7301         crWaitUntilV(pktin);\r
7302         if (pktin->type != SSH2_MSG_KEXRSA_DONE) {\r
7303             sfree(s->rsakeydata);\r
7304             bombout(("expected signature packet from server"));\r
7305             crStopV;\r
7306         }\r
7308         ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen);\r
7309         if (!s->sigdata) {\r
7310             bombout(("unable to parse signature packet"));\r
7311             crStopV;\r
7312         }\r
7314         sfree(s->rsakeydata);\r
7315     }\r
7317     hash_mpint(ssh->kex->hash, ssh->exhash, s->K);\r
7318     assert(ssh->kex->hash->hlen <= sizeof(s->exchange_hash));\r
7319     ssh->kex->hash->final(ssh->exhash, s->exchange_hash);\r
7321     ssh->kex_ctx = NULL;\r
7323 #if 0\r
7324     debug(("Exchange hash is:\n"));\r
7325     dmemdump(s->exchange_hash, ssh->kex->hash->hlen);\r
7326 #endif\r
7328     if (!s->hkey) {\r
7329         bombout(("Server's host key is invalid"));\r
7330         crStopV;\r
7331     }\r
7333     if (!ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,\r
7334                                  (char *)s->exchange_hash,\r
7335                                  ssh->kex->hash->hlen)) {\r
7336 #ifndef FUZZING\r
7337         bombout(("Server's host key did not match the signature supplied"));\r
7338         crStopV;\r
7339 #endif\r
7340     }\r
7342     s->keystr = ssh->hostkey->fmtkey(s->hkey);\r
7343     if (!s->got_session_id) {\r
7344         /*\r
7345          * Make a note of any other host key formats that are available.\r
7346          */\r
7347         {\r
7348             int i, j, nkeys = 0;\r
7349             char *list = NULL;\r
7350             for (i = 0; i < lenof(hostkey_algs); i++) {\r
7351                 if (hostkey_algs[i].alg == ssh->hostkey)\r
7352                     continue;\r
7354                 for (j = 0; j < ssh->n_uncert_hostkeys; j++)\r
7355                     if (ssh->uncert_hostkeys[j] == i)\r
7356                         break;\r
7358                 if (j < ssh->n_uncert_hostkeys) {\r
7359                     char *newlist;\r
7360                     if (list)\r
7361                         newlist = dupprintf("%s/%s", list,\r
7362                                             hostkey_algs[i].alg->name);\r
7363                     else\r
7364                         newlist = dupprintf("%s", hostkey_algs[i].alg->name);\r
7365                     sfree(list);\r
7366                     list = newlist;\r
7367                     nkeys++;\r
7368                 }\r
7369             }\r
7370             if (list) {\r
7371                 logeventf(ssh,\r
7372                           "Server also has %s host key%s, but we "\r
7373                           "don't know %s", list,\r
7374                           nkeys > 1 ? "s" : "",\r
7375                           nkeys > 1 ? "any of them" : "it");\r
7376                 sfree(list);\r
7377             }\r
7378         }\r
7380         /*\r
7381          * Authenticate remote host: verify host key. (We've already\r
7382          * checked the signature of the exchange hash.)\r
7383          */\r
7384         s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey);\r
7385         logevent("Host key fingerprint is:");\r
7386         logevent(s->fingerprint);\r
7387         /* First check against manually configured host keys. */\r
7388         s->dlgret = verify_ssh_manual_host_key(ssh, s->fingerprint,\r
7389                                                ssh->hostkey, s->hkey);\r
7390         if (s->dlgret == 0) {          /* did not match */\r
7391             bombout(("Host key did not appear in manually configured list"));\r
7392             crStopV;\r
7393         } else if (s->dlgret < 0) { /* none configured; use standard handling */\r
7394             ssh_set_frozen(ssh, 1);\r
7395             s->dlgret = verify_ssh_host_key(ssh->frontend,\r
7396                                             ssh->savedhost, ssh->savedport,\r
7397                                             ssh->hostkey->keytype, s->keystr,\r
7398                                             s->fingerprint,\r
7399                                             ssh_dialog_callback, ssh);\r
7400 #ifdef FUZZING\r
7401             s->dlgret = 1;\r
7402 #endif\r
7403             if (s->dlgret < 0) {\r
7404                 do {\r
7405                     crReturnV;\r
7406                     if (pktin) {\r
7407                         bombout(("Unexpected data from server while waiting"\r
7408                                  " for user host key response"));\r
7409                         crStopV;\r
7410                     }\r
7411                 } while (pktin || inlen > 0);\r
7412                 s->dlgret = ssh->user_response;\r
7413             }\r
7414             ssh_set_frozen(ssh, 0);\r
7415             if (s->dlgret == 0) {\r
7416                 ssh_disconnect(ssh, "Aborted at host key verification", NULL,\r
7417                                0, TRUE);\r
7418                 crStopV;\r
7419             }\r
7420         }\r
7421         sfree(s->fingerprint);\r
7422         /*\r
7423          * Save this host key, to check against the one presented in\r
7424          * subsequent rekeys.\r
7425          */\r
7426         ssh->hostkey_str = s->keystr;\r
7427     } else if (ssh->cross_certifying) {\r
7428         s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey);\r
7429         logevent("Storing additional host key for this host:");\r
7430         logevent(s->fingerprint);\r
7431         sfree(s->fingerprint);\r
7432         store_host_key(ssh->savedhost, ssh->savedport,\r
7433                        ssh->hostkey->keytype, s->keystr);\r
7434         ssh->cross_certifying = FALSE;\r
7435         /*\r
7436          * Don't forget to store the new key as the one we'll be\r
7437          * re-checking in future normal rekeys.\r
7438          */\r
7439         ssh->hostkey_str = s->keystr;\r
7440     } else {\r
7441         /*\r
7442          * In a rekey, we never present an interactive host key\r
7443          * verification request to the user. Instead, we simply\r
7444          * enforce that the key we're seeing this time is identical to\r
7445          * the one we saw before.\r
7446          */\r
7447         if (strcmp(ssh->hostkey_str, s->keystr)) {\r
7448 #ifndef FUZZING\r
7449             bombout(("Host key was different in repeat key exchange"));\r
7450             crStopV;\r
7451 #endif\r
7452         }\r
7453         sfree(s->keystr);\r
7454     }\r
7455     ssh->hostkey->freekey(s->hkey);\r
7457     /*\r
7458      * The exchange hash from the very first key exchange is also\r
7459      * the session id, used in session key construction and\r
7460      * authentication.\r
7461      */\r
7462     if (!s->got_session_id) {\r
7463         assert(sizeof(s->exchange_hash) <= sizeof(ssh->v2_session_id));\r
7464         memcpy(ssh->v2_session_id, s->exchange_hash,\r
7465                sizeof(s->exchange_hash));\r
7466         ssh->v2_session_id_len = ssh->kex->hash->hlen;\r
7467         assert(ssh->v2_session_id_len <= sizeof(ssh->v2_session_id));\r
7468         s->got_session_id = TRUE;\r
7469     }\r
7471     /*\r
7472      * Send SSH2_MSG_NEWKEYS.\r
7473      */\r
7474     s->pktout = ssh2_pkt_init(SSH2_MSG_NEWKEYS);\r
7475     ssh2_pkt_send_noqueue(ssh, s->pktout);\r
7476     ssh->outgoing_data_size = 0;       /* start counting from here */\r
7478     /*\r
7479      * We've sent client NEWKEYS, so create and initialise\r
7480      * client-to-server session keys.\r
7481      */\r
7482     if (ssh->cs_cipher_ctx)\r
7483         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
7484     ssh->cscipher = s->cscipher_tobe;\r
7485     if (ssh->cscipher) ssh->cs_cipher_ctx = ssh->cscipher->make_context();\r
7487     if (ssh->cs_mac_ctx)\r
7488         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
7489     ssh->csmac = s->csmac_tobe;\r
7490     ssh->csmac_etm = s->csmac_etm_tobe;\r
7491     if (ssh->csmac)\r
7492         ssh->cs_mac_ctx = ssh->csmac->make_context(ssh->cs_cipher_ctx);\r
7494     if (ssh->cs_comp_ctx)\r
7495         ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
7496     ssh->cscomp = s->cscomp_tobe;\r
7497     ssh->cs_comp_ctx = ssh->cscomp->compress_init();\r
7499     /*\r
7500      * Set IVs on client-to-server keys. Here we use the exchange\r
7501      * hash from the _first_ key exchange.\r
7502      */\r
7503     if (ssh->cscipher) {\r
7504         unsigned char *key;\r
7506         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'C',\r
7507                          ssh->cscipher->padded_keybytes);\r
7508         ssh->cscipher->setkey(ssh->cs_cipher_ctx, key);\r
7509         smemclr(key, ssh->cscipher->padded_keybytes);\r
7510         sfree(key);\r
7512         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'A',\r
7513                          ssh->cscipher->blksize);\r
7514         ssh->cscipher->setiv(ssh->cs_cipher_ctx, key);\r
7515         smemclr(key, ssh->cscipher->blksize);\r
7516         sfree(key);\r
7517     }\r
7518     if (ssh->csmac) {\r
7519         unsigned char *key;\r
7521         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'E',\r
7522                          ssh->csmac->keylen);\r
7523         ssh->csmac->setkey(ssh->cs_mac_ctx, key);\r
7524         smemclr(key, ssh->csmac->keylen);\r
7525         sfree(key);\r
7526     }\r
7528     if (ssh->cscipher)\r
7529         logeventf(ssh, "Initialised %.200s client->server encryption",\r
7530                   ssh->cscipher->text_name);\r
7531     if (ssh->csmac)\r
7532         logeventf(ssh, "Initialised %.200s client->server MAC algorithm%s%s",\r
7533                   ssh->csmac->text_name,\r
7534                   ssh->csmac_etm ? " (in ETM mode)" : "",\r
7535                   ssh->cscipher->required_mac ? " (required by cipher)" : "");\r
7536     if (ssh->cscomp->text_name)\r
7537         logeventf(ssh, "Initialised %s compression",\r
7538                   ssh->cscomp->text_name);\r
7540     /*\r
7541      * Now our end of the key exchange is complete, we can send all\r
7542      * our queued higher-layer packets.\r
7543      */\r
7544     ssh->queueing = FALSE;\r
7545     ssh2_pkt_queuesend(ssh);\r
7547     /*\r
7548      * Expect SSH2_MSG_NEWKEYS from server.\r
7549      */\r
7550     crWaitUntilV(pktin);\r
7551     if (pktin->type != SSH2_MSG_NEWKEYS) {\r
7552         bombout(("expected new-keys packet from server"));\r
7553         crStopV;\r
7554     }\r
7555     ssh->incoming_data_size = 0;       /* start counting from here */\r
7557     /*\r
7558      * We've seen server NEWKEYS, so create and initialise\r
7559      * server-to-client session keys.\r
7560      */\r
7561     if (ssh->sc_cipher_ctx)\r
7562         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
7563     if (s->sccipher_tobe) {\r
7564         ssh->sccipher = s->sccipher_tobe;\r
7565         ssh->sc_cipher_ctx = ssh->sccipher->make_context();\r
7566     }\r
7568     if (ssh->sc_mac_ctx)\r
7569         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
7570     if (s->scmac_tobe) {\r
7571         ssh->scmac = s->scmac_tobe;\r
7572         ssh->scmac_etm = s->scmac_etm_tobe;\r
7573         ssh->sc_mac_ctx = ssh->scmac->make_context(ssh->sc_cipher_ctx);\r
7574     }\r
7576     if (ssh->sc_comp_ctx)\r
7577         ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
7578     ssh->sccomp = s->sccomp_tobe;\r
7579     ssh->sc_comp_ctx = ssh->sccomp->decompress_init();\r
7581     /*\r
7582      * Set IVs on server-to-client keys. Here we use the exchange\r
7583      * hash from the _first_ key exchange.\r
7584      */\r
7585     if (ssh->sccipher) {\r
7586         unsigned char *key;\r
7588         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'D',\r
7589                          ssh->sccipher->padded_keybytes);\r
7590         ssh->sccipher->setkey(ssh->sc_cipher_ctx, key);\r
7591         smemclr(key, ssh->sccipher->padded_keybytes);\r
7592         sfree(key);\r
7594         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'B',\r
7595                          ssh->sccipher->blksize);\r
7596         ssh->sccipher->setiv(ssh->sc_cipher_ctx, key);\r
7597         smemclr(key, ssh->sccipher->blksize);\r
7598         sfree(key);\r
7599     }\r
7600     if (ssh->scmac) {\r
7601         unsigned char *key;\r
7603         key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'F',\r
7604                          ssh->scmac->keylen);\r
7605         ssh->scmac->setkey(ssh->sc_mac_ctx, key);\r
7606         smemclr(key, ssh->scmac->keylen);\r
7607         sfree(key);\r
7608     }\r
7609     if (ssh->sccipher)\r
7610         logeventf(ssh, "Initialised %.200s server->client encryption",\r
7611                   ssh->sccipher->text_name);\r
7612     if (ssh->scmac)\r
7613         logeventf(ssh, "Initialised %.200s server->client MAC algorithm%s%s",\r
7614                   ssh->scmac->text_name,\r
7615                   ssh->scmac_etm ? " (in ETM mode)" : "",\r
7616                   ssh->sccipher->required_mac ? " (required by cipher)" : "");\r
7617     if (ssh->sccomp->text_name)\r
7618         logeventf(ssh, "Initialised %s decompression",\r
7619                   ssh->sccomp->text_name);\r
7621     /*\r
7622      * Free shared secret.\r
7623      */\r
7624     freebn(s->K);\r
7626     /*\r
7627      * Update the specials menu to list the remaining uncertified host\r
7628      * keys.\r
7629      */\r
7630     update_specials_menu(ssh->frontend);\r
7632     /*\r
7633      * Key exchange is over. Loop straight back round if we have a\r
7634      * deferred rekey reason.\r
7635      */\r
7636     if (ssh->deferred_rekey_reason) {\r
7637         logevent(ssh->deferred_rekey_reason);\r
7638         pktin = NULL;\r
7639         ssh->deferred_rekey_reason = NULL;\r
7640         goto begin_key_exchange;\r
7641     }\r
7643     /*\r
7644      * Otherwise, schedule a timer for our next rekey.\r
7645      */\r
7646     ssh->kex_in_progress = FALSE;\r
7647     ssh->last_rekey = GETTICKCOUNT();\r
7648     if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0)\r
7649         ssh->next_rekey = schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC,\r
7650                                          ssh2_timer, ssh);\r
7652     /*\r
7653      * Now we're encrypting. Begin returning 1 to the protocol main\r
7654      * function so that other things can run on top of the\r
7655      * transport. If we ever see a KEXINIT, we must go back to the\r
7656      * start.\r
7657      * \r
7658      * We _also_ go back to the start if we see pktin==NULL and\r
7659      * inlen negative, because this is a special signal meaning\r
7660      * `initiate client-driven rekey', and `in' contains a message\r
7661      * giving the reason for the rekey.\r
7662      *\r
7663      * inlen==-1 means always initiate a rekey;\r
7664      * inlen==-2 means that userauth has completed successfully and\r
7665      *   we should consider rekeying (for delayed compression).\r
7666      */\r
7667     while (!((pktin && pktin->type == SSH2_MSG_KEXINIT) ||\r
7668              (!pktin && inlen < 0))) {\r
7669         wait_for_rekey:\r
7670         if (!ssh->protocol_initial_phase_done) {\r
7671             ssh->protocol_initial_phase_done = TRUE;\r
7672             /*\r
7673              * Allow authconn to initialise itself.\r
7674              */\r
7675             do_ssh2_authconn(ssh, NULL, 0, NULL);\r
7676         }\r
7677         crReturnV;\r
7678     }\r
7679     if (pktin) {\r
7680         logevent("Server initiated key re-exchange");\r
7681     } else {\r
7682         if (inlen == -2) {\r
7683             /* \r
7684              * authconn has seen a USERAUTH_SUCCEEDED. Time to enable\r
7685              * delayed compression, if it's available.\r
7686              *\r
7687              * draft-miller-secsh-compression-delayed-00 says that you\r
7688              * negotiate delayed compression in the first key exchange, and\r
7689              * both sides start compressing when the server has sent\r
7690              * USERAUTH_SUCCESS. This has a race condition -- the server\r
7691              * can't know when the client has seen it, and thus which incoming\r
7692              * packets it should treat as compressed.\r
7693              *\r
7694              * Instead, we do the initial key exchange without offering the\r
7695              * delayed methods, but note if the server offers them; when we\r
7696              * get here, if a delayed method was available that was higher\r
7697              * on our list than what we got, we initiate a rekey in which we\r
7698              * _do_ list the delayed methods (and hopefully get it as a\r
7699              * result). Subsequent rekeys will do the same.\r
7700              */\r
7701             assert(!s->userauth_succeeded); /* should only happen once */\r
7702             s->userauth_succeeded = TRUE;\r
7703             if (!s->pending_compression)\r
7704                 /* Can't see any point rekeying. */\r
7705                 goto wait_for_rekey;       /* this is utterly horrid */\r
7706             /* else fall through to rekey... */\r
7707             s->pending_compression = FALSE;\r
7708         }\r
7709         /*\r
7710          * Now we've decided to rekey.\r
7711          *\r
7712          * Special case: if the server bug is set that doesn't\r
7713          * allow rekeying, we give a different log message and\r
7714          * continue waiting. (If such a server _initiates_ a rekey,\r
7715          * we process it anyway!)\r
7716          */\r
7717         if ((ssh->remote_bugs & BUG_SSH2_REKEY)) {\r
7718             logeventf(ssh, "Server bug prevents key re-exchange (%s)",\r
7719                       (char *)in);\r
7720             /* Reset the counters, so that at least this message doesn't\r
7721              * hit the event log _too_ often. */\r
7722             ssh->outgoing_data_size = 0;\r
7723             ssh->incoming_data_size = 0;\r
7724             if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0) {\r
7725                 ssh->next_rekey =\r
7726                     schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC,\r
7727                                    ssh2_timer, ssh);\r
7728             }\r
7729             goto wait_for_rekey;       /* this is still utterly horrid */\r
7730         } else {\r
7731             logeventf(ssh, "Initiating key re-exchange (%s)", (char *)in);\r
7732         }\r
7733     }\r
7734     goto begin_key_exchange;\r
7736     crFinishV;\r
7739 /*\r
7740  * Send data on an SSH channel.  In SSH-2, this involves buffering it\r
7741  * first.\r
7742  */\r
7743 static int ssh_send_channel_data(struct ssh_channel *c, const char *buf,\r
7744                                    int len)\r
7746     if (c->ssh->version == 2) {\r
7747         bufchain_add(&c->v.v2.outbuffer, buf, len);\r
7748         return ssh2_try_send(c);\r
7749     } else {\r
7750         send_packet(c->ssh, SSH1_MSG_CHANNEL_DATA,\r
7751                     PKT_INT, c->remoteid,\r
7752                     PKT_INT, len,\r
7753                     PKT_DATA, buf, len,\r
7754                     PKT_END);\r
7755         /*\r
7756          * In SSH-1 we can return 0 here - implying that channels are\r
7757          * never individually throttled - because the only\r
7758          * circumstance that can cause throttling will be the whole\r
7759          * SSH connection backing up, in which case _everything_ will\r
7760          * be throttled as a whole.\r
7761          */\r
7762         return 0;\r
7763     }\r
7766 /*\r
7767  * Attempt to send data on an SSH-2 channel.\r
7768  */\r
7769 static int ssh2_try_send(struct ssh_channel *c)\r
7771     Ssh ssh = c->ssh;\r
7772     struct Packet *pktout;\r
7773     int ret;\r
7775     while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) {\r
7776         int len;\r
7777         void *data;\r
7778         bufchain_prefix(&c->v.v2.outbuffer, &data, &len);\r
7779         if ((unsigned)len > c->v.v2.remwindow)\r
7780             len = c->v.v2.remwindow;\r
7781         if ((unsigned)len > c->v.v2.remmaxpkt)\r
7782             len = c->v.v2.remmaxpkt;\r
7783         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);\r
7784         ssh2_pkt_adduint32(pktout, c->remoteid);\r
7785         ssh2_pkt_addstring_start(pktout);\r
7786         ssh2_pkt_addstring_data(pktout, data, len);\r
7787         ssh2_pkt_send(ssh, pktout);\r
7788         bufchain_consume(&c->v.v2.outbuffer, len);\r
7789         c->v.v2.remwindow -= len;\r
7790     }\r
7792     /*\r
7793      * After having sent as much data as we can, return the amount\r
7794      * still buffered.\r
7795      */\r
7796     ret = bufchain_size(&c->v.v2.outbuffer);\r
7798     /*\r
7799      * And if there's no data pending but we need to send an EOF, send\r
7800      * it.\r
7801      */\r
7802     if (!ret && c->pending_eof)\r
7803         ssh_channel_try_eof(c);\r
7805     return ret;\r
7808 static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c)\r
7810     int bufsize;\r
7811     if (c->closes & CLOSES_SENT_EOF)\r
7812         return;                   /* don't send on channels we've EOFed */\r
7813     bufsize = ssh2_try_send(c);\r
7814     if (bufsize == 0) {\r
7815         switch (c->type) {\r
7816           case CHAN_MAINSESSION:\r
7817             /* stdin need not receive an unthrottle\r
7818              * notification since it will be polled */\r
7819             break;\r
7820           case CHAN_X11:\r
7821             x11_unthrottle(c->u.x11.xconn);\r
7822             break;\r
7823           case CHAN_AGENT:\r
7824             /* Now that we've successfully sent all the outgoing\r
7825              * replies we had, try to process more incoming data. */\r
7826             ssh_agentf_try_forward(c);\r
7827             break;\r
7828           case CHAN_SOCKDATA:\r
7829             pfd_unthrottle(c->u.pfd.pf);\r
7830             break;\r
7831         }\r
7832     }\r
7835 static int ssh_is_simple(Ssh ssh)\r
7837     /*\r
7838      * We use the 'simple' variant of the SSH protocol if we're asked\r
7839      * to, except not if we're also doing connection-sharing (either\r
7840      * tunnelling our packets over an upstream or expecting to be\r
7841      * tunnelled over ourselves), since then the assumption that we\r
7842      * have only one channel to worry about is not true after all.\r
7843      */\r
7844     return (conf_get_int(ssh->conf, CONF_ssh_simple) &&\r
7845             !ssh->bare_connection && !ssh->connshare);\r
7848 /*\r
7849  * Set up most of a new ssh_channel.\r
7850  */\r
7851 static void ssh_channel_init(struct ssh_channel *c)\r
7853     Ssh ssh = c->ssh;\r
7854     c->localid = alloc_channel_id(ssh);\r
7855     c->closes = 0;\r
7856     c->pending_eof = FALSE;\r
7857     c->throttling_conn = FALSE;\r
7858     if (ssh->version == 2) {\r
7859         c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =\r
7860             ssh_is_simple(ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;\r
7861         c->v.v2.chanreq_head = NULL;\r
7862         c->v.v2.throttle_state = UNTHROTTLED;\r
7863         bufchain_init(&c->v.v2.outbuffer);\r
7864     }\r
7865     add234(ssh->channels, c);\r
7868 /*\r
7869  * Construct the common parts of a CHANNEL_OPEN.\r
7870  */\r
7871 static struct Packet *ssh2_chanopen_init(struct ssh_channel *c,\r
7872                                          const char *type)\r
7874     struct Packet *pktout;\r
7876     pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);\r
7877     ssh2_pkt_addstring(pktout, type);\r
7878     ssh2_pkt_adduint32(pktout, c->localid);\r
7879     ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */\r
7880     ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
7881     return pktout;\r
7884 /*\r
7885  * CHANNEL_FAILURE doesn't come with any indication of what message\r
7886  * caused it, so we have to keep track of the outstanding\r
7887  * CHANNEL_REQUESTs ourselves.\r
7888  */\r
7889 static void ssh2_queue_chanreq_handler(struct ssh_channel *c,\r
7890                                        cchandler_fn_t handler, void *ctx)\r
7892     struct outstanding_channel_request *ocr =\r
7893         snew(struct outstanding_channel_request);\r
7895     assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));\r
7896     ocr->handler = handler;\r
7897     ocr->ctx = ctx;\r
7898     ocr->next = NULL;\r
7899     if (!c->v.v2.chanreq_head)\r
7900         c->v.v2.chanreq_head = ocr;\r
7901     else\r
7902         c->v.v2.chanreq_tail->next = ocr;\r
7903     c->v.v2.chanreq_tail = ocr;\r
7906 /*\r
7907  * Construct the common parts of a CHANNEL_REQUEST.  If handler is not\r
7908  * NULL then a reply will be requested and the handler will be called\r
7909  * when it arrives.  The returned packet is ready to have any\r
7910  * request-specific data added and be sent.  Note that if a handler is\r
7911  * provided, it's essential that the request actually be sent.\r
7912  *\r
7913  * The handler will usually be passed the response packet in pktin. If\r
7914  * pktin is NULL, this means that no reply will ever be forthcoming\r
7915  * (e.g. because the entire connection is being destroyed, or because\r
7916  * the server initiated channel closure before we saw the response)\r
7917  * and the handler should free any storage it's holding.\r
7918  */\r
7919 static struct Packet *ssh2_chanreq_init(struct ssh_channel *c,\r
7920                                         const char *type,\r
7921                                         cchandler_fn_t handler, void *ctx)\r
7923     struct Packet *pktout;\r
7925     assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));\r
7926     pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);\r
7927     ssh2_pkt_adduint32(pktout, c->remoteid);\r
7928     ssh2_pkt_addstring(pktout, type);\r
7929     ssh2_pkt_addbool(pktout, handler != NULL);\r
7930     if (handler != NULL)\r
7931         ssh2_queue_chanreq_handler(c, handler, ctx);\r
7932     return pktout;\r
7935 static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize)\r
7937     Ssh ssh = c->ssh;\r
7938     int buflimit;\r
7940     if (ssh->version == 1) {\r
7941         buflimit = SSH1_BUFFER_LIMIT;\r
7942     } else {\r
7943         if (ssh_is_simple(ssh))\r
7944             buflimit = 0;\r
7945         else\r
7946             buflimit = c->v.v2.locmaxwin;\r
7947         if (bufsize < buflimit)\r
7948             ssh2_set_window(c, buflimit - bufsize);\r
7949     }\r
7950     if (c->throttling_conn && bufsize <= buflimit) {\r
7951         c->throttling_conn = 0;\r
7952         ssh_throttle_conn(ssh, -1);\r
7953     }\r
7956 /*\r
7957  * Potentially enlarge the window on an SSH-2 channel.\r
7958  */\r
7959 static void ssh2_handle_winadj_response(struct ssh_channel *, struct Packet *,\r
7960                                         void *);\r
7961 static void ssh2_set_window(struct ssh_channel *c, int newwin)\r
7963     Ssh ssh = c->ssh;\r
7965     /*\r
7966      * Never send WINDOW_ADJUST for a channel that the remote side has\r
7967      * already sent EOF on; there's no point, since it won't be\r
7968      * sending any more data anyway. Ditto if _we've_ already sent\r
7969      * CLOSE.\r
7970      */\r
7971     if (c->closes & (CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))\r
7972         return;\r
7974     /*\r
7975      * Also, never widen the window for an X11 channel when we're\r
7976      * still waiting to see its initial auth and may yet hand it off\r
7977      * to a downstream.\r
7978      */\r
7979     if (c->type == CHAN_X11 && c->u.x11.initial)\r
7980         return;\r
7982     /*\r
7983      * If the remote end has a habit of ignoring maxpkt, limit the\r
7984      * window so that it has no choice (assuming it doesn't ignore the\r
7985      * window as well).\r
7986      */\r
7987     if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT)\r
7988         newwin = OUR_V2_MAXPKT;\r
7990     /*\r
7991      * Only send a WINDOW_ADJUST if there's significantly more window\r
7992      * available than the other end thinks there is.  This saves us\r
7993      * sending a WINDOW_ADJUST for every character in a shell session.\r
7994      *\r
7995      * "Significant" is arbitrarily defined as half the window size.\r
7996      */\r
7997     if (newwin / 2 >= c->v.v2.locwindow) {\r
7998         struct Packet *pktout;\r
7999         unsigned *up;\r
8001         /*\r
8002          * In order to keep track of how much window the client\r
8003          * actually has available, we'd like it to acknowledge each\r
8004          * WINDOW_ADJUST.  We can't do that directly, so we accompany\r
8005          * it with a CHANNEL_REQUEST that has to be acknowledged.\r
8006          *\r
8007          * This is only necessary if we're opening the window wide.\r
8008          * If we're not, then throughput is being constrained by\r
8009          * something other than the maximum window size anyway.\r
8010          */\r
8011         if (newwin == c->v.v2.locmaxwin &&\r
8012             !(ssh->remote_bugs & BUG_CHOKES_ON_WINADJ)) {\r
8013             up = snew(unsigned);\r
8014             *up = newwin - c->v.v2.locwindow;\r
8015             pktout = ssh2_chanreq_init(c, "winadj@putty.projects.tartarus.org",\r
8016                                        ssh2_handle_winadj_response, up);\r
8017             ssh2_pkt_send(ssh, pktout);\r
8019             if (c->v.v2.throttle_state != UNTHROTTLED)\r
8020                 c->v.v2.throttle_state = UNTHROTTLING;\r
8021         } else {\r
8022             /* Pretend the WINDOW_ADJUST was acked immediately. */\r
8023             c->v.v2.remlocwin = newwin;\r
8024             c->v.v2.throttle_state = THROTTLED;\r
8025         }\r
8026         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);\r
8027         ssh2_pkt_adduint32(pktout, c->remoteid);\r
8028         ssh2_pkt_adduint32(pktout, newwin - c->v.v2.locwindow);\r
8029         ssh2_pkt_send(ssh, pktout);\r
8030         c->v.v2.locwindow = newwin;\r
8031     }\r
8034 /*\r
8035  * Find the channel associated with a message.  If there's no channel,\r
8036  * or it's not properly open, make a noise about it and return NULL.\r
8037  * If the channel is shared, pass the message on to downstream and\r
8038  * also return NULL (meaning the caller should ignore this message).\r
8039  */\r
8040 static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin)\r
8042     unsigned localid = ssh_pkt_getuint32(pktin);\r
8043     struct ssh_channel *c;\r
8044     int halfopen_ok;\r
8046     /* Is this message OK on a half-open connection? */\r
8047     if (ssh->version == 1)\r
8048         halfopen_ok = (pktin->type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION ||\r
8049                        pktin->type == SSH1_MSG_CHANNEL_OPEN_FAILURE);\r
8050     else\r
8051         halfopen_ok = (pktin->type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION ||\r
8052                        pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
8053     c = find234(ssh->channels, &localid, ssh_channelfind);\r
8054     if (!c || (c->type != CHAN_SHARING && (c->halfopen != halfopen_ok))) {\r
8055         char *buf = dupprintf("Received %s for %s channel %u",\r
8056                               ssh_pkt_type(ssh, pktin->type),\r
8057                               !c ? "nonexistent" :\r
8058                               c->halfopen ? "half-open" : "open",\r
8059                               localid);\r
8060         ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
8061         sfree(buf);\r
8062         return NULL;\r
8063     }\r
8064     if (c->type == CHAN_SHARING) {\r
8065         share_got_pkt_from_server(c->u.sharing.ctx, pktin->type,\r
8066                                   pktin->body, pktin->length);\r
8067         return NULL;\r
8068     }\r
8069     return c;\r
8072 static void ssh2_handle_winadj_response(struct ssh_channel *c,\r
8073                                         struct Packet *pktin, void *ctx)\r
8075     unsigned *sizep = ctx;\r
8077     /*\r
8078      * Winadj responses should always be failures. However, at least\r
8079      * one server ("boks_sshd") is known to return SUCCESS for channel\r
8080      * requests it's never heard of, such as "winadj@putty". Raised\r
8081      * with foxt.com as bug 090916-090424, but for the sake of a quiet\r
8082      * life, we don't worry about what kind of response we got.\r
8083      */\r
8085     c->v.v2.remlocwin += *sizep;\r
8086     sfree(sizep);\r
8087     /*\r
8088      * winadj messages are only sent when the window is fully open, so\r
8089      * if we get an ack of one, we know any pending unthrottle is\r
8090      * complete.\r
8091      */\r
8092     if (c->v.v2.throttle_state == UNTHROTTLING)\r
8093         c->v.v2.throttle_state = UNTHROTTLED;\r
8096 static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin)\r
8098     struct ssh_channel *c = ssh_channel_msg(ssh, pktin);\r
8099     struct outstanding_channel_request *ocr;\r
8101     if (!c) return;\r
8102     ocr = c->v.v2.chanreq_head;\r
8103     if (!ocr) {\r
8104         ssh2_msg_unexpected(ssh, pktin);\r
8105         return;\r
8106     }\r
8107     ocr->handler(c, pktin, ocr->ctx);\r
8108     c->v.v2.chanreq_head = ocr->next;\r
8109     sfree(ocr);\r
8110     /*\r
8111      * We may now initiate channel-closing procedures, if that\r
8112      * CHANNEL_REQUEST was the last thing outstanding before we send\r
8113      * CHANNEL_CLOSE.\r
8114      */\r
8115     ssh2_channel_check_close(c);\r
8118 static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)\r
8120     struct ssh_channel *c;\r
8121     c = ssh_channel_msg(ssh, pktin);\r
8122     if (!c)\r
8123         return;\r
8124     if (!(c->closes & CLOSES_SENT_EOF)) {\r
8125         c->v.v2.remwindow += ssh_pkt_getuint32(pktin);\r
8126         ssh2_try_send_and_unthrottle(ssh, c);\r
8127     }\r
8130 static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)\r
8132     char *data;\r
8133     int length;\r
8134     unsigned ext_type = 0; /* 0 means not extended */\r
8135     struct ssh_channel *c;\r
8136     c = ssh_channel_msg(ssh, pktin);\r
8137     if (!c)\r
8138         return;\r
8139     if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)\r
8140         ext_type = ssh_pkt_getuint32(pktin);\r
8141     ssh_pkt_getstring(pktin, &data, &length);\r
8142     if (data) {\r
8143         int bufsize;\r
8144         c->v.v2.locwindow -= length;\r
8145         c->v.v2.remlocwin -= length;\r
8146         if (ext_type != 0 && ext_type != SSH2_EXTENDED_DATA_STDERR)\r
8147             length = 0; /* Don't do anything with unknown extended data. */\r
8148         bufsize = ssh_channel_data(c, ext_type == SSH2_EXTENDED_DATA_STDERR,\r
8149                                    data, length);\r
8150         /*\r
8151          * If it looks like the remote end hit the end of its window,\r
8152          * and we didn't want it to do that, think about using a\r
8153          * larger window.\r
8154          */\r
8155         if (c->v.v2.remlocwin <= 0 && c->v.v2.throttle_state == UNTHROTTLED &&\r
8156             c->v.v2.locmaxwin < 0x40000000)\r
8157             c->v.v2.locmaxwin += OUR_V2_WINSIZE;\r
8158         /*\r
8159          * If we are not buffering too much data,\r
8160          * enlarge the window again at the remote side.\r
8161          * If we are buffering too much, we may still\r
8162          * need to adjust the window if the server's\r
8163          * sent excess data.\r
8164          */\r
8165         if (bufsize < c->v.v2.locmaxwin)\r
8166             ssh2_set_window(c, c->v.v2.locmaxwin - bufsize);\r
8167         /*\r
8168          * If we're either buffering way too much data, or if we're\r
8169          * buffering anything at all and we're in "simple" mode,\r
8170          * throttle the whole channel.\r
8171          */\r
8172         if ((bufsize > c->v.v2.locmaxwin || (ssh_is_simple(ssh) && bufsize>0))\r
8173             && !c->throttling_conn) {\r
8174             c->throttling_conn = 1;\r
8175             ssh_throttle_conn(ssh, +1);\r
8176         }\r
8177     }\r
8180 static void ssh_check_termination(Ssh ssh)\r
8182     if (ssh->version == 2 &&\r
8183         !conf_get_int(ssh->conf, CONF_ssh_no_shell) &&\r
8184         (ssh->channels && count234(ssh->channels) == 0) &&\r
8185         !(ssh->connshare && share_ndownstreams(ssh->connshare) > 0)) {\r
8186         /*\r
8187          * We used to send SSH_MSG_DISCONNECT here, because I'd\r
8188          * believed that _every_ conforming SSH-2 connection had to\r
8189          * end with a disconnect being sent by at least one side;\r
8190          * apparently I was wrong and it's perfectly OK to\r
8191          * unceremoniously slam the connection shut when you're done,\r
8192          * and indeed OpenSSH feels this is more polite than sending a\r
8193          * DISCONNECT. So now we don't.\r
8194          */\r
8195         ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE);\r
8196     }\r
8199 void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,\r
8200                                       const char *peerinfo)\r
8202     if (peerinfo)\r
8203         logeventf(ssh, "Connection sharing downstream #%u connected from %s",\r
8204                   id, peerinfo);\r
8205     else\r
8206         logeventf(ssh, "Connection sharing downstream #%u connected", id);\r
8209 void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id)\r
8211     logeventf(ssh, "Connection sharing downstream #%u disconnected", id);\r
8212     ssh_check_termination(ssh);\r
8215 void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...)\r
8217     va_list ap;\r
8218     char *buf;\r
8220     va_start(ap, logfmt);\r
8221     buf = dupvprintf(logfmt, ap);\r
8222     va_end(ap);\r
8223     if (id)\r
8224         logeventf(ssh, "Connection sharing downstream #%u: %s", id, buf);\r
8225     else\r
8226         logeventf(ssh, "Connection sharing: %s", buf);\r
8227     sfree(buf);\r
8230 /*\r
8231  * Close any local socket and free any local resources associated with\r
8232  * a channel.  This converts the channel into a CHAN_ZOMBIE.\r
8233  */\r
8234 static void ssh_channel_close_local(struct ssh_channel *c, char const *reason)\r
8236     Ssh ssh = c->ssh;\r
8237     char const *msg = NULL;\r
8239     switch (c->type) {\r
8240       case CHAN_MAINSESSION:\r
8241         ssh->mainchan = NULL;\r
8242         update_specials_menu(ssh->frontend);\r
8243         break;\r
8244       case CHAN_X11:\r
8245         assert(c->u.x11.xconn != NULL);\r
8246         x11_close(c->u.x11.xconn);\r
8247         msg = "Forwarded X11 connection terminated";\r
8248         break;\r
8249       case CHAN_AGENT:\r
8250         if (c->u.a.pending)\r
8251             agent_cancel_query(c->u.a.pending);\r
8252         bufchain_clear(&c->u.a.inbuffer);\r
8253         msg = "Agent-forwarding connection closed";\r
8254         break;\r
8255       case CHAN_SOCKDATA:\r
8256         assert(c->u.pfd.pf != NULL);\r
8257         pfd_close(c->u.pfd.pf);\r
8258         msg = "Forwarded port closed";\r
8259         break;\r
8260     }\r
8261     c->type = CHAN_ZOMBIE;\r
8262     if (msg != NULL) {\r
8263         if (reason != NULL)\r
8264             logeventf(ssh, "%s %s", msg, reason);\r
8265         else\r
8266             logevent(msg);\r
8267     }\r
8270 static void ssh_channel_destroy(struct ssh_channel *c)\r
8272     Ssh ssh = c->ssh;\r
8274     ssh_channel_close_local(c, NULL);\r
8276     del234(ssh->channels, c);\r
8277     if (ssh->version == 2) {\r
8278         bufchain_clear(&c->v.v2.outbuffer);\r
8279         assert(c->v.v2.chanreq_head == NULL);\r
8280     }\r
8281     sfree(c);\r
8283     /*\r
8284      * If that was the last channel left open, we might need to\r
8285      * terminate.\r
8286      */\r
8287     ssh_check_termination(ssh);\r
8290 static void ssh2_channel_check_close(struct ssh_channel *c)\r
8292     Ssh ssh = c->ssh;\r
8293     struct Packet *pktout;\r
8295     assert(ssh->version == 2);\r
8296     if (c->halfopen) {\r
8297         /*\r
8298          * If we've sent out our own CHANNEL_OPEN but not yet seen\r
8299          * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then\r
8300          * it's too early to be sending close messages of any kind.\r
8301          */\r
8302         return;\r
8303     }\r
8305     if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) ||\r
8306          c->type == CHAN_ZOMBIE) &&\r
8307         !c->v.v2.chanreq_head &&\r
8308         !(c->closes & CLOSES_SENT_CLOSE)) {\r
8309         /*\r
8310          * We have both sent and received EOF (or the channel is a\r
8311          * zombie), and we have no outstanding channel requests, which\r
8312          * means the channel is in final wind-up. But we haven't sent\r
8313          * CLOSE, so let's do so now.\r
8314          */\r
8315         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);\r
8316         ssh2_pkt_adduint32(pktout, c->remoteid);\r
8317         ssh2_pkt_send(ssh, pktout);\r
8318         c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE;\r
8319     }\r
8321     if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) {\r
8322         assert(c->v.v2.chanreq_head == NULL);\r
8323         /*\r
8324          * We have both sent and received CLOSE, which means we're\r
8325          * completely done with the channel.\r
8326          */\r
8327         ssh_channel_destroy(c);\r
8328     }\r
8331 static void ssh_channel_got_eof(struct ssh_channel *c)\r
8333     if (c->closes & CLOSES_RCVD_EOF)\r
8334         return;                        /* already seen EOF */\r
8335     c->closes |= CLOSES_RCVD_EOF;\r
8337     if (c->type == CHAN_X11) {\r
8338         assert(c->u.x11.xconn != NULL);\r
8339         x11_send_eof(c->u.x11.xconn);\r
8340     } else if (c->type == CHAN_AGENT) {\r
8341         /* Just call try_forward, which will respond to the EOF now if\r
8342          * appropriate, or wait until the queue of outstanding\r
8343          * requests is dealt with if not */\r
8344         ssh_agentf_try_forward(c);\r
8345     } else if (c->type == CHAN_SOCKDATA) {\r
8346         assert(c->u.pfd.pf != NULL);\r
8347         pfd_send_eof(c->u.pfd.pf);\r
8348     } else if (c->type == CHAN_MAINSESSION) {\r
8349         Ssh ssh = c->ssh;\r
8351         if (!ssh->sent_console_eof &&\r
8352             (from_backend_eof(ssh->frontend) || ssh->got_pty)) {\r
8353             /*\r
8354              * Either from_backend_eof told us that the front end\r
8355              * wants us to close the outgoing side of the connection\r
8356              * as soon as we see EOF from the far end, or else we've\r
8357              * unilaterally decided to do that because we've allocated\r
8358              * a remote pty and hence EOF isn't a particularly\r
8359              * meaningful concept.\r
8360              */\r
8361             sshfwd_write_eof(c);\r
8362         }\r
8363         ssh->sent_console_eof = TRUE;\r
8364     }\r
8367 static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin)\r
8369     struct ssh_channel *c;\r
8371     c = ssh_channel_msg(ssh, pktin);\r
8372     if (!c)\r
8373         return;\r
8374     ssh_channel_got_eof(c);\r
8375     ssh2_channel_check_close(c);\r
8378 static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)\r
8380     struct ssh_channel *c;\r
8382     c = ssh_channel_msg(ssh, pktin);\r
8383     if (!c)\r
8384         return;\r
8386     /*\r
8387      * When we receive CLOSE on a channel, we assume it comes with an\r
8388      * implied EOF if we haven't seen EOF yet.\r
8389      */\r
8390     ssh_channel_got_eof(c);\r
8392     if (!(ssh->remote_bugs & BUG_SENDS_LATE_REQUEST_REPLY)) {\r
8393         /*\r
8394          * It also means we stop expecting to see replies to any\r
8395          * outstanding channel requests, so clean those up too.\r
8396          * (ssh_chanreq_init will enforce by assertion that we don't\r
8397          * subsequently put anything back on this list.)\r
8398          */\r
8399         while (c->v.v2.chanreq_head) {\r
8400             struct outstanding_channel_request *ocr = c->v.v2.chanreq_head;\r
8401             ocr->handler(c, NULL, ocr->ctx);\r
8402             c->v.v2.chanreq_head = ocr->next;\r
8403             sfree(ocr);\r
8404         }\r
8405     }\r
8407     /*\r
8408      * And we also send an outgoing EOF, if we haven't already, on the\r
8409      * assumption that CLOSE is a pretty forceful announcement that\r
8410      * the remote side is doing away with the entire channel. (If it\r
8411      * had wanted to send us EOF and continue receiving data from us,\r
8412      * it would have just sent CHANNEL_EOF.)\r
8413      */\r
8414     if (!(c->closes & CLOSES_SENT_EOF)) {\r
8415         /*\r
8416          * Make sure we don't read any more from whatever our local\r
8417          * data source is for this channel.\r
8418          */\r
8419         switch (c->type) {\r
8420           case CHAN_MAINSESSION:\r
8421             ssh->send_ok = 0;     /* stop trying to read from stdin */\r
8422             break;\r
8423           case CHAN_X11:\r
8424             x11_override_throttle(c->u.x11.xconn, 1);\r
8425             break;\r
8426           case CHAN_SOCKDATA:\r
8427             pfd_override_throttle(c->u.pfd.pf, 1);\r
8428             break;\r
8429         }\r
8431         /*\r
8432          * Abandon any buffered data we still wanted to send to this\r
8433          * channel. Receiving a CHANNEL_CLOSE is an indication that\r
8434          * the server really wants to get on and _destroy_ this\r
8435          * channel, and it isn't going to send us any further\r
8436          * WINDOW_ADJUSTs to permit us to send pending stuff.\r
8437          */\r
8438         bufchain_clear(&c->v.v2.outbuffer);\r
8440         /*\r
8441          * Send outgoing EOF.\r
8442          */\r
8443         sshfwd_write_eof(c);\r
8444     }\r
8446     /*\r
8447      * Now process the actual close.\r
8448      */\r
8449     if (!(c->closes & CLOSES_RCVD_CLOSE)) {\r
8450         c->closes |= CLOSES_RCVD_CLOSE;\r
8451         ssh2_channel_check_close(c);\r
8452     }\r
8455 static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)\r
8457     struct ssh_channel *c;\r
8459     c = ssh_channel_msg(ssh, pktin);\r
8460     if (!c)\r
8461         return;\r
8462     assert(c->halfopen); /* ssh_channel_msg will have enforced this */\r
8463     c->remoteid = ssh_pkt_getuint32(pktin);\r
8464     c->halfopen = FALSE;\r
8465     c->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
8466     c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
8468     if (c->type == CHAN_SOCKDATA) {\r
8469         assert(c->u.pfd.pf != NULL);\r
8470         pfd_confirm(c->u.pfd.pf);\r
8471     } else if (c->type == CHAN_ZOMBIE) {\r
8472         /*\r
8473          * This case can occur if a local socket error occurred\r
8474          * between us sending out CHANNEL_OPEN and receiving\r
8475          * OPEN_CONFIRMATION. In this case, all we can do is\r
8476          * immediately initiate close proceedings now that we know the\r
8477          * server's id to put in the close message.\r
8478          */\r
8479         ssh2_channel_check_close(c);\r
8480     } else {\r
8481         /*\r
8482          * We never expect to receive OPEN_CONFIRMATION for any\r
8483          * *other* channel type (since only local-to-remote port\r
8484          * forwardings cause us to send CHANNEL_OPEN after the main\r
8485          * channel is live - all other auxiliary channel types are\r
8486          * initiated from the server end). It's safe to enforce this\r
8487          * by assertion rather than by ssh_disconnect, because the\r
8488          * real point is that we never constructed a half-open channel\r
8489          * structure in the first place with any type other than the\r
8490          * above.\r
8491          */\r
8492         assert(!"Funny channel type in ssh2_msg_channel_open_confirmation");\r
8493     }\r
8495     if (c->pending_eof)\r
8496         ssh_channel_try_eof(c);        /* in case we had a pending EOF */\r
8499 static char *ssh2_channel_open_failure_error_text(struct Packet *pktin)\r
8501     static const char *const reasons[] = {\r
8502         NULL,\r
8503         "Administratively prohibited",\r
8504         "Connect failed",\r
8505         "Unknown channel type",\r
8506         "Resource shortage",\r
8507     };\r
8508     unsigned reason_code;\r
8509     const char *reason_code_string;\r
8510     char reason_code_buf[256];\r
8511     char *reason_string;\r
8512     int reason_length;\r
8514     reason_code = ssh_pkt_getuint32(pktin);\r
8515     if (reason_code < lenof(reasons) && reasons[reason_code]) {\r
8516         reason_code_string = reasons[reason_code];\r
8517     } else {\r
8518         reason_code_string = reason_code_buf;\r
8519         sprintf(reason_code_buf, "unknown reason code %#x", reason_code);\r
8520     }\r
8522     ssh_pkt_getstring(pktin, &reason_string, &reason_length);\r
8524     return dupprintf("%s [%.*s]", reason_code_string,\r
8525                      reason_length, NULLTOEMPTY(reason_string));\r
8528 static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)\r
8530     struct ssh_channel *c;\r
8532     c = ssh_channel_msg(ssh, pktin);\r
8533     if (!c)\r
8534         return;\r
8535     assert(c->halfopen); /* ssh_channel_msg will have enforced this */\r
8537     if (c->type == CHAN_SOCKDATA) {\r
8538         char *errtext = ssh2_channel_open_failure_error_text(pktin);\r
8539         logeventf(ssh, "Forwarded connection refused by server: %s", errtext);\r
8540         sfree(errtext);\r
8541         pfd_close(c->u.pfd.pf);\r
8542     } else if (c->type == CHAN_ZOMBIE) {\r
8543         /*\r
8544          * This case can occur if a local socket error occurred\r
8545          * between us sending out CHANNEL_OPEN and receiving\r
8546          * OPEN_FAILURE. In this case, we need do nothing except allow\r
8547          * the code below to throw the half-open channel away.\r
8548          */\r
8549     } else {\r
8550         /*\r
8551          * We never expect to receive OPEN_FAILURE for any *other*\r
8552          * channel type (since only local-to-remote port forwardings\r
8553          * cause us to send CHANNEL_OPEN after the main channel is\r
8554          * live - all other auxiliary channel types are initiated from\r
8555          * the server end). It's safe to enforce this by assertion\r
8556          * rather than by ssh_disconnect, because the real point is\r
8557          * that we never constructed a half-open channel structure in\r
8558          * the first place with any type other than the above.\r
8559          */\r
8560         assert(!"Funny channel type in ssh2_msg_channel_open_failure");\r
8561     }\r
8563     del234(ssh->channels, c);\r
8564     sfree(c);\r
8567 static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin)\r
8569     char *type;\r
8570     int typelen, want_reply;\r
8571     int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */\r
8572     struct ssh_channel *c;\r
8573     struct Packet *pktout;\r
8575     c = ssh_channel_msg(ssh, pktin);\r
8576     if (!c)\r
8577         return;\r
8578     ssh_pkt_getstring(pktin, &type, &typelen);\r
8579     want_reply = ssh2_pkt_getbool(pktin);\r
8581     if (c->closes & CLOSES_SENT_CLOSE) {\r
8582         /*\r
8583          * We don't reply to channel requests after we've sent\r
8584          * CHANNEL_CLOSE for the channel, because our reply might\r
8585          * cross in the network with the other side's CHANNEL_CLOSE\r
8586          * and arrive after they have wound the channel up completely.\r
8587          */\r
8588         want_reply = FALSE;\r
8589     }\r
8591     /*\r
8592      * Having got the channel number, we now look at\r
8593      * the request type string to see if it's something\r
8594      * we recognise.\r
8595      */\r
8596     if (c == ssh->mainchan) {\r
8597         /*\r
8598          * We recognise "exit-status" and "exit-signal" on\r
8599          * the primary channel.\r
8600          */\r
8601         if (typelen == 11 &&\r
8602             !memcmp(type, "exit-status", 11)) {\r
8604             ssh->exitcode = ssh_pkt_getuint32(pktin);\r
8605             logeventf(ssh, "Server sent command exit status %d",\r
8606                       ssh->exitcode);\r
8607             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
8609         } else if (typelen == 11 &&\r
8610                    !memcmp(type, "exit-signal", 11)) {\r
8612             int is_plausible = TRUE, is_int = FALSE;\r
8613             char *fmt_sig = NULL, *fmt_msg = NULL;\r
8614             char *msg;\r
8615             int msglen = 0, core = FALSE;\r
8616             /* ICK: older versions of OpenSSH (e.g. 3.4p1)\r
8617              * provide an `int' for the signal, despite its\r
8618              * having been a `string' in the drafts of RFC 4254 since at\r
8619              * least 2001. (Fixed in session.c 1.147.) Try to\r
8620              * infer which we can safely parse it as. */\r
8621             {\r
8622                 unsigned char *p = pktin->body +\r
8623                     pktin->savedpos;\r
8624                 long len = pktin->length - pktin->savedpos;\r
8625                 unsigned long num = GET_32BIT(p); /* what is it? */\r
8626                 /* If it's 0, it hardly matters; assume string */\r
8627                 if (num == 0) {\r
8628                     is_int = FALSE;\r
8629                 } else {\r
8630                     int maybe_int = FALSE, maybe_str = FALSE;\r
8631 #define CHECK_HYPOTHESIS(offset, result)                                \\r
8632                     do                                                  \\r
8633                     {                                                   \\r
8634                         int q = toint(offset);                          \\r
8635                         if (q >= 0 && q+4 <= len) {                     \\r
8636                             q = toint(q + 4 + GET_32BIT(p+q));          \\r
8637                             if (q >= 0 && q+4 <= len &&                 \\r
8638                                 ((q = toint(q + 4 + GET_32BIT(p+q))) != 0) && \\r
8639                                 q == len)                               \\r
8640                                 result = TRUE;                          \\r
8641                         }                                               \\r
8642                     } while(0)\r
8643                     CHECK_HYPOTHESIS(4+1, maybe_int);\r
8644                     CHECK_HYPOTHESIS(4+num+1, maybe_str);\r
8645 #undef CHECK_HYPOTHESIS\r
8646                     if (maybe_int && !maybe_str)\r
8647                         is_int = TRUE;\r
8648                     else if (!maybe_int && maybe_str)\r
8649                         is_int = FALSE;\r
8650                     else\r
8651                         /* Crikey. Either or neither. Panic. */\r
8652                         is_plausible = FALSE;\r
8653                 }\r
8654             }\r
8655             ssh->exitcode = 128;       /* means `unknown signal' */\r
8656             if (is_plausible) {\r
8657                 if (is_int) {\r
8658                     /* Old non-standard OpenSSH. */\r
8659                     int signum = ssh_pkt_getuint32(pktin);\r
8660                     fmt_sig = dupprintf(" %d", signum);\r
8661                     ssh->exitcode = 128 + signum;\r
8662                 } else {\r
8663                     /* As per RFC 4254. */\r
8664                     char *sig;\r
8665                     int siglen;\r
8666                     ssh_pkt_getstring(pktin, &sig, &siglen);\r
8667                     /* Signal name isn't supposed to be blank, but\r
8668                      * let's cope gracefully if it is. */\r
8669                     if (siglen) {\r
8670                         fmt_sig = dupprintf(" \"%.*s\"",\r
8671                                             siglen, sig);\r
8672                     }\r
8674                     /*\r
8675                      * Really hideous method of translating the\r
8676                      * signal description back into a locally\r
8677                      * meaningful number.\r
8678                      */\r
8680                     if (0)\r
8681                         ;\r
8682 #define TRANSLATE_SIGNAL(s) \\r
8683     else if (siglen == lenof(#s)-1 && !memcmp(sig, #s, siglen)) \\r
8684         ssh->exitcode = 128 + SIG ## s\r
8685 #ifdef SIGABRT\r
8686                     TRANSLATE_SIGNAL(ABRT);\r
8687 #endif\r
8688 #ifdef SIGALRM\r
8689                     TRANSLATE_SIGNAL(ALRM);\r
8690 #endif\r
8691 #ifdef SIGFPE\r
8692                     TRANSLATE_SIGNAL(FPE);\r
8693 #endif\r
8694 #ifdef SIGHUP\r
8695                     TRANSLATE_SIGNAL(HUP);\r
8696 #endif\r
8697 #ifdef SIGILL\r
8698                     TRANSLATE_SIGNAL(ILL);\r
8699 #endif\r
8700 #ifdef SIGINT\r
8701                     TRANSLATE_SIGNAL(INT);\r
8702 #endif\r
8703 #ifdef SIGKILL\r
8704                     TRANSLATE_SIGNAL(KILL);\r
8705 #endif\r
8706 #ifdef SIGPIPE\r
8707                     TRANSLATE_SIGNAL(PIPE);\r
8708 #endif\r
8709 #ifdef SIGQUIT\r
8710                     TRANSLATE_SIGNAL(QUIT);\r
8711 #endif\r
8712 #ifdef SIGSEGV\r
8713                     TRANSLATE_SIGNAL(SEGV);\r
8714 #endif\r
8715 #ifdef SIGTERM\r
8716                     TRANSLATE_SIGNAL(TERM);\r
8717 #endif\r
8718 #ifdef SIGUSR1\r
8719                     TRANSLATE_SIGNAL(USR1);\r
8720 #endif\r
8721 #ifdef SIGUSR2\r
8722                     TRANSLATE_SIGNAL(USR2);\r
8723 #endif\r
8724 #undef TRANSLATE_SIGNAL\r
8725                     else\r
8726                         ssh->exitcode = 128;\r
8727                 }\r
8728                 core = ssh2_pkt_getbool(pktin);\r
8729                 ssh_pkt_getstring(pktin, &msg, &msglen);\r
8730                 if (msglen) {\r
8731                     fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg);\r
8732                 }\r
8733                 /* ignore lang tag */\r
8734             } /* else don't attempt to parse */\r
8735             logeventf(ssh, "Server exited on signal%s%s%s",\r
8736                       fmt_sig ? fmt_sig : "",\r
8737                       core ? " (core dumped)" : "",\r
8738                       fmt_msg ? fmt_msg : "");\r
8739             sfree(fmt_sig);\r
8740             sfree(fmt_msg);\r
8741             reply = SSH2_MSG_CHANNEL_SUCCESS;\r
8743         }\r
8744     } else {\r
8745         /*\r
8746          * This is a channel request we don't know\r
8747          * about, so we now either ignore the request\r
8748          * or respond with CHANNEL_FAILURE, depending\r
8749          * on want_reply.\r
8750          */\r
8751         reply = SSH2_MSG_CHANNEL_FAILURE;\r
8752     }\r
8753     if (want_reply) {\r
8754         pktout = ssh2_pkt_init(reply);\r
8755         ssh2_pkt_adduint32(pktout, c->remoteid);\r
8756         ssh2_pkt_send(ssh, pktout);\r
8757     }\r
8760 static void ssh2_msg_global_request(Ssh ssh, struct Packet *pktin)\r
8762     char *type;\r
8763     int typelen, want_reply;\r
8764     struct Packet *pktout;\r
8766     ssh_pkt_getstring(pktin, &type, &typelen);\r
8767     want_reply = ssh2_pkt_getbool(pktin);\r
8769     /*\r
8770      * We currently don't support any global requests\r
8771      * at all, so we either ignore the request or\r
8772      * respond with REQUEST_FAILURE, depending on\r
8773      * want_reply.\r
8774      */\r
8775     if (want_reply) {\r
8776         pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE);\r
8777         ssh2_pkt_send(ssh, pktout);\r
8778     }\r
8781 struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype,\r
8782                                                 void *share_cs,\r
8783                                                 void *share_chan)\r
8785     struct X11FakeAuth *auth;\r
8787     /*\r
8788      * Make up a new set of fake X11 auth data, and add it to the tree\r
8789      * of currently valid ones with an indication of the sharing\r
8790      * context that it's relevant to.\r
8791      */\r
8792     auth = x11_invent_fake_auth(ssh->x11authtree, authtype);\r
8793     auth->share_cs = share_cs;\r
8794     auth->share_chan = share_chan;\r
8796     return auth;\r
8799 void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth)\r
8801     del234(ssh->x11authtree, auth);\r
8802     x11_free_fake_auth(auth);\r
8805 static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)\r
8807     char *type;\r
8808     int typelen;\r
8809     char *peeraddr;\r
8810     int peeraddrlen;\r
8811     int peerport;\r
8812     const char *error = NULL;\r
8813     struct ssh_channel *c;\r
8814     unsigned remid, winsize, pktsize;\r
8815     unsigned our_winsize_override = 0;\r
8816     struct Packet *pktout;\r
8818     ssh_pkt_getstring(pktin, &type, &typelen);\r
8819     c = snew(struct ssh_channel);\r
8820     c->ssh = ssh;\r
8822     remid = ssh_pkt_getuint32(pktin);\r
8823     winsize = ssh_pkt_getuint32(pktin);\r
8824     pktsize = ssh_pkt_getuint32(pktin);\r
8826     if (typelen == 3 && !memcmp(type, "x11", 3)) {\r
8827         char *addrstr;\r
8829         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
8830         addrstr = dupprintf("%.*s", peeraddrlen, NULLTOEMPTY(peeraddr));\r
8831         peerport = ssh_pkt_getuint32(pktin);\r
8833         logeventf(ssh, "Received X11 connect request from %s:%d",\r
8834                   addrstr, peerport);\r
8836         if (!ssh->X11_fwd_enabled && !ssh->connshare)\r
8837             error = "X11 forwarding is not enabled";\r
8838         else {\r
8839             c->u.x11.xconn = x11_init(ssh->x11authtree, c,\r
8840                                       addrstr, peerport);\r
8841             c->type = CHAN_X11;\r
8842             c->u.x11.initial = TRUE;\r
8844             /*\r
8845              * If we are a connection-sharing upstream, then we should\r
8846              * initially present a very small window, adequate to take\r
8847              * the X11 initial authorisation packet but not much more.\r
8848              * Downstream will then present us a larger window (by\r
8849              * fiat of the connection-sharing protocol) and we can\r
8850              * guarantee to send a positive-valued WINDOW_ADJUST.\r
8851              */\r
8852             if (ssh->connshare)\r
8853                 our_winsize_override = 128;\r
8855             logevent("Opened X11 forward channel");\r
8856         }\r
8858         sfree(addrstr);\r
8859     } else if (typelen == 15 &&\r
8860                !memcmp(type, "forwarded-tcpip", 15)) {\r
8861         struct ssh_rportfwd pf, *realpf;\r
8862         char *shost;\r
8863         int shostlen;\r
8864         ssh_pkt_getstring(pktin, &shost, &shostlen);/* skip address */\r
8865         pf.shost = dupprintf("%.*s", shostlen, NULLTOEMPTY(shost));\r
8866         pf.sport = ssh_pkt_getuint32(pktin);\r
8867         ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);\r
8868         peerport = ssh_pkt_getuint32(pktin);\r
8869         realpf = find234(ssh->rportfwds, &pf, NULL);\r
8870         logeventf(ssh, "Received remote port %s:%d open request "\r
8871                   "from %.*s:%d", pf.shost, pf.sport,\r
8872                   peeraddrlen, NULLTOEMPTY(peeraddr), peerport);\r
8873         sfree(pf.shost);\r
8875         if (realpf == NULL) {\r
8876             error = "Remote port is not recognised";\r
8877         } else {\r
8878             char *err;\r
8880             if (realpf->share_ctx) {\r
8881                 /*\r
8882                  * This port forwarding is on behalf of a\r
8883                  * connection-sharing downstream, so abandon our own\r
8884                  * channel-open procedure and just pass the message on\r
8885                  * to sshshare.c.\r
8886                  */\r
8887                 share_got_pkt_from_server(realpf->share_ctx, pktin->type,\r
8888                                           pktin->body, pktin->length);\r
8889                 sfree(c);\r
8890                 return;\r
8891             }\r
8893             err = pfd_connect(&c->u.pfd.pf, realpf->dhost, realpf->dport,\r
8894                               c, ssh->conf, realpf->pfrec->addressfamily);\r
8895             logeventf(ssh, "Attempting to forward remote port to "\r
8896                       "%s:%d", realpf->dhost, realpf->dport);\r
8897             if (err != NULL) {\r
8898                 logeventf(ssh, "Port open failed: %s", err);\r
8899                 sfree(err);\r
8900                 error = "Port open failed";\r
8901             } else {\r
8902                 logevent("Forwarded port opened successfully");\r
8903                 c->type = CHAN_SOCKDATA;\r
8904             }\r
8905         }\r
8906     } else if (typelen == 22 &&\r
8907                !memcmp(type, "auth-agent@openssh.com", 22)) {\r
8908         if (!ssh->agentfwd_enabled)\r
8909             error = "Agent forwarding is not enabled";\r
8910         else {\r
8911             c->type = CHAN_AGENT;       /* identify channel type */\r
8912             bufchain_init(&c->u.a.inbuffer);\r
8913             c->u.a.pending = NULL;\r
8914         }\r
8915     } else {\r
8916         error = "Unsupported channel type requested";\r
8917     }\r
8919     c->remoteid = remid;\r
8920     c->halfopen = FALSE;\r
8921     if (error) {\r
8922         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);\r
8923         ssh2_pkt_adduint32(pktout, c->remoteid);\r
8924         ssh2_pkt_adduint32(pktout, SSH2_OPEN_CONNECT_FAILED);\r
8925         ssh2_pkt_addstring(pktout, error);\r
8926         ssh2_pkt_addstring(pktout, "en");       /* language tag */\r
8927         ssh2_pkt_send(ssh, pktout);\r
8928         logeventf(ssh, "Rejected channel open: %s", error);\r
8929         sfree(c);\r
8930     } else {\r
8931         ssh_channel_init(c);\r
8932         c->v.v2.remwindow = winsize;\r
8933         c->v.v2.remmaxpkt = pktsize;\r
8934         if (our_winsize_override) {\r
8935             c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =\r
8936                 our_winsize_override;\r
8937         }\r
8938         pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);\r
8939         ssh2_pkt_adduint32(pktout, c->remoteid);\r
8940         ssh2_pkt_adduint32(pktout, c->localid);\r
8941         ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);\r
8942         ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */\r
8943         ssh2_pkt_send(ssh, pktout);\r
8944     }\r
8947 void sshfwd_x11_sharing_handover(struct ssh_channel *c,\r
8948                                  void *share_cs, void *share_chan,\r
8949                                  const char *peer_addr, int peer_port,\r
8950                                  int endian, int protomajor, int protominor,\r
8951                                  const void *initial_data, int initial_len)\r
8953     /*\r
8954      * This function is called when we've just discovered that an X\r
8955      * forwarding channel on which we'd been handling the initial auth\r
8956      * ourselves turns out to be destined for a connection-sharing\r
8957      * downstream. So we turn the channel into a CHAN_SHARING, meaning\r
8958      * that we completely stop tracking windows and buffering data and\r
8959      * just pass more or less unmodified SSH messages back and forth.\r
8960      */\r
8961     c->type = CHAN_SHARING;\r
8962     c->u.sharing.ctx = share_cs;\r
8963     share_setup_x11_channel(share_cs, share_chan,\r
8964                             c->localid, c->remoteid, c->v.v2.remwindow,\r
8965                             c->v.v2.remmaxpkt, c->v.v2.locwindow,\r
8966                             peer_addr, peer_port, endian,\r
8967                             protomajor, protominor,\r
8968                             initial_data, initial_len);\r
8971 void sshfwd_x11_is_local(struct ssh_channel *c)\r
8973     /*\r
8974      * This function is called when we've just discovered that an X\r
8975      * forwarding channel is _not_ destined for a connection-sharing\r
8976      * downstream but we're going to handle it ourselves. We stop\r
8977      * presenting a cautiously small window and go into ordinary data\r
8978      * exchange mode.\r
8979      */\r
8980     c->u.x11.initial = FALSE;\r
8981     ssh2_set_window(c, ssh_is_simple(c->ssh) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE);\r
8984 /*\r
8985  * Buffer banner messages for later display at some convenient point,\r
8986  * if we're going to display them.\r
8987  */\r
8988 static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin)\r
8990     /* Arbitrary limit to prevent unbounded inflation of buffer */\r
8991     if (conf_get_int(ssh->conf, CONF_ssh_show_banner) &&\r
8992         bufchain_size(&ssh->banner) <= 131072) {\r
8993         char *banner = NULL;\r
8994         int size = 0;\r
8995         ssh_pkt_getstring(pktin, &banner, &size);\r
8996         if (banner)\r
8997             bufchain_add(&ssh->banner, banner, size);\r
8998     }\r
9001 /* Helper function to deal with sending tty modes for "pty-req" */\r
9002 static void ssh2_send_ttymode(void *data,\r
9003                               const struct ssh_ttymode *mode, char *val)\r
9005     struct Packet *pktout = (struct Packet *)data;\r
9006     unsigned int arg = 0;\r
9008     switch (mode->type) {\r
9009       case TTY_OP_CHAR:\r
9010         arg = ssh_tty_parse_specchar(val);\r
9011         break;\r
9012       case TTY_OP_BOOL:\r
9013         arg = ssh_tty_parse_boolean(val);\r
9014         break;\r
9015     }\r
9016     ssh2_pkt_addbyte(pktout, mode->opcode);\r
9017     ssh2_pkt_adduint32(pktout, arg);\r
9020 static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin,\r
9021                            void *ctx)\r
9023     struct ssh2_setup_x11_state {\r
9024         int crLine;\r
9025     };\r
9026     Ssh ssh = c->ssh;\r
9027     struct Packet *pktout;\r
9028     crStateP(ssh2_setup_x11_state, ctx);\r
9030     crBeginState;\r
9032     logevent("Requesting X11 forwarding");\r
9033     pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req",\r
9034                                ssh2_setup_x11, s);\r
9035     ssh2_pkt_addbool(pktout, 0);               /* many connections */\r
9036     ssh2_pkt_addstring(pktout, ssh->x11auth->protoname);\r
9037     ssh2_pkt_addstring(pktout, ssh->x11auth->datastring);\r
9038     ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum);\r
9039     ssh2_pkt_send(ssh, pktout);\r
9041     /* Wait to be called back with either a response packet, or NULL\r
9042      * meaning clean up and free our data */\r
9043     crReturnV;\r
9045     if (pktin) {\r
9046         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
9047             logevent("X11 forwarding enabled");\r
9048             ssh->X11_fwd_enabled = TRUE;\r
9049         } else\r
9050             logevent("X11 forwarding refused");\r
9051     }\r
9053     crFinishFreeV;\r
9056 static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin,\r
9057                                    void *ctx)\r
9059     struct ssh2_setup_agent_state {\r
9060         int crLine;\r
9061     };\r
9062     Ssh ssh = c->ssh;\r
9063     struct Packet *pktout;\r
9064     crStateP(ssh2_setup_agent_state, ctx);\r
9066     crBeginState;\r
9068     logevent("Requesting OpenSSH-style agent forwarding");\r
9069     pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com",\r
9070                                ssh2_setup_agent, s);\r
9071     ssh2_pkt_send(ssh, pktout);\r
9073     /* Wait to be called back with either a response packet, or NULL\r
9074      * meaning clean up and free our data */\r
9075     crReturnV;\r
9077     if (pktin) {\r
9078         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
9079             logevent("Agent forwarding enabled");\r
9080             ssh->agentfwd_enabled = TRUE;\r
9081         } else\r
9082             logevent("Agent forwarding refused");\r
9083     }\r
9085     crFinishFreeV;\r
9088 static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin,\r
9089                                  void *ctx)\r
9091     struct ssh2_setup_pty_state {\r
9092         int crLine;\r
9093     };\r
9094     Ssh ssh = c->ssh;\r
9095     struct Packet *pktout;\r
9096     crStateP(ssh2_setup_pty_state, ctx);\r
9098     crBeginState;\r
9100     /* Unpick the terminal-speed string. */\r
9101     /* XXX perhaps we should allow no speeds to be sent. */\r
9102     ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */\r
9103     sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);\r
9104     /* Build the pty request. */\r
9105     pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req",\r
9106                                ssh2_setup_pty, s);\r
9107     ssh2_pkt_addstring(pktout, conf_get_str(ssh->conf, CONF_termtype));\r
9108     ssh2_pkt_adduint32(pktout, ssh->term_width);\r
9109     ssh2_pkt_adduint32(pktout, ssh->term_height);\r
9110     ssh2_pkt_adduint32(pktout, 0);             /* pixel width */\r
9111     ssh2_pkt_adduint32(pktout, 0);             /* pixel height */\r
9112     ssh2_pkt_addstring_start(pktout);\r
9113     parse_ttymodes(ssh, ssh2_send_ttymode, (void *)pktout);\r
9114     ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_ISPEED);\r
9115     ssh2_pkt_adduint32(pktout, ssh->ispeed);\r
9116     ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_OSPEED);\r
9117     ssh2_pkt_adduint32(pktout, ssh->ospeed);\r
9118     ssh2_pkt_addstring_data(pktout, "\0", 1); /* TTY_OP_END */\r
9119     ssh2_pkt_send(ssh, pktout);\r
9120     ssh->state = SSH_STATE_INTERMED;\r
9122     /* Wait to be called back with either a response packet, or NULL\r
9123      * meaning clean up and free our data */\r
9124     crReturnV;\r
9126     if (pktin) {\r
9127         if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {\r
9128             logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",\r
9129                       ssh->ospeed, ssh->ispeed);\r
9130             ssh->got_pty = TRUE;\r
9131         } else {\r
9132             c_write_str(ssh, "Server refused to allocate pty\r\n");\r
9133             ssh->editing = ssh->echoing = 1;\r
9134         }\r
9135     }\r
9137     crFinishFreeV;\r
9140 static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,\r
9141                            void *ctx)\r
9143     struct ssh2_setup_env_state {\r
9144         int crLine;\r
9145         int num_env, env_left, env_ok;\r
9146     };\r
9147     Ssh ssh = c->ssh;\r
9148     struct Packet *pktout;\r
9149     crStateP(ssh2_setup_env_state, ctx);\r
9151     crBeginState;\r
9153     /*\r
9154      * Send environment variables.\r
9155      * \r
9156      * Simplest thing here is to send all the requests at once, and\r
9157      * then wait for a whole bunch of successes or failures.\r
9158      */\r
9159     s->num_env = 0;\r
9160     {\r
9161         char *key, *val;\r
9163         for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key);\r
9164              val != NULL;\r
9165              val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) {\r
9166             pktout = ssh2_chanreq_init(ssh->mainchan, "env", ssh2_setup_env, s);\r
9167             ssh2_pkt_addstring(pktout, key);\r
9168             ssh2_pkt_addstring(pktout, val);\r
9169             ssh2_pkt_send(ssh, pktout);\r
9171             s->num_env++;\r
9172         }\r
9173         if (s->num_env)\r
9174             logeventf(ssh, "Sent %d environment variables", s->num_env);\r
9175     }\r
9177     if (s->num_env) {\r
9178         s->env_ok = 0;\r
9179         s->env_left = s->num_env;\r
9181         while (s->env_left > 0) {\r
9182             /* Wait to be called back with either a response packet,\r
9183              * or NULL meaning clean up and free our data */\r
9184             crReturnV;\r
9185             if (!pktin) goto out;\r
9186             if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS)\r
9187                 s->env_ok++;\r
9188             s->env_left--;\r
9189         }\r
9191         if (s->env_ok == s->num_env) {\r
9192             logevent("All environment variables successfully set");\r
9193         } else if (s->env_ok == 0) {\r
9194             logevent("All environment variables refused");\r
9195             c_write_str(ssh, "Server refused to set environment variables\r\n");\r
9196         } else {\r
9197             logeventf(ssh, "%d environment variables refused",\r
9198                       s->num_env - s->env_ok);\r
9199             c_write_str(ssh, "Server refused to set all environment variables\r\n");\r
9200         }\r
9201     }\r
9202   out:;\r
9203     crFinishFreeV;\r
9206 /*\r
9207  * Handle the SSH-2 userauth and connection layers.\r
9208  */\r
9209 static void ssh2_msg_authconn(Ssh ssh, struct Packet *pktin)\r
9211     do_ssh2_authconn(ssh, NULL, 0, pktin);\r
9214 static void ssh2_response_authconn(struct ssh_channel *c, struct Packet *pktin,\r
9215                                    void *ctx)\r
9217     if (pktin)\r
9218         do_ssh2_authconn(c->ssh, NULL, 0, pktin);\r
9221 static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,\r
9222                              struct Packet *pktin)\r
9224     struct do_ssh2_authconn_state {\r
9225         int crLine;\r
9226         enum {\r
9227             AUTH_TYPE_NONE,\r
9228                 AUTH_TYPE_PUBLICKEY,\r
9229                 AUTH_TYPE_PUBLICKEY_OFFER_LOUD,\r
9230                 AUTH_TYPE_PUBLICKEY_OFFER_QUIET,\r
9231                 AUTH_TYPE_PASSWORD,\r
9232                 AUTH_TYPE_GSSAPI,      /* always QUIET */\r
9233                 AUTH_TYPE_KEYBOARD_INTERACTIVE,\r
9234                 AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET\r
9235         } type;\r
9236         int done_service_req;\r
9237         int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;\r
9238         int tried_pubkey_config, done_agent;\r
9239 #ifndef NO_GSSAPI\r
9240         int can_gssapi;\r
9241         int tried_gssapi;\r
9242 #endif\r
9243         int kbd_inter_refused;\r
9244         int we_are_in, userauth_success;\r
9245         prompts_t *cur_prompt;\r
9246         int num_prompts;\r
9247         char *username;\r
9248         char *password;\r
9249         int got_username;\r
9250         void *publickey_blob;\r
9251         int publickey_bloblen;\r
9252         int privatekey_available, privatekey_encrypted;\r
9253         char *publickey_algorithm;\r
9254         char *publickey_comment;\r
9255         unsigned char agent_request[5], *agent_response, *agentp;\r
9256         int agent_responselen;\r
9257         unsigned char *pkblob_in_agent;\r
9258         int keyi, nkeys;\r
9259         char *pkblob, *alg, *commentp;\r
9260         int pklen, alglen, commentlen;\r
9261         int siglen, retlen, len;\r
9262         char *q, *agentreq, *ret;\r
9263         struct Packet *pktout;\r
9264         Filename *keyfile;\r
9265 #ifndef NO_GSSAPI\r
9266         struct ssh_gss_library *gsslib;\r
9267         Ssh_gss_ctx gss_ctx;\r
9268         Ssh_gss_buf gss_buf;\r
9269         Ssh_gss_buf gss_rcvtok, gss_sndtok;\r
9270         Ssh_gss_name gss_srv_name;\r
9271         Ssh_gss_stat gss_stat;\r
9272 #endif\r
9273     };\r
9274     crState(do_ssh2_authconn_state);\r
9276     crBeginState;\r
9278     /* Register as a handler for all the messages this coroutine handles. */\r
9279     ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_authconn;\r
9280     ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_authconn;\r
9281     ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_authconn;\r
9282     ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_authconn;\r
9283     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_authconn;\r
9284     ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_authconn;\r
9285     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_authconn; duplicate case value */\r
9286     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_authconn; duplicate case value */\r
9287     ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_authconn;\r
9288     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_authconn;\r
9289     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_authconn;\r
9290     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_authconn;\r
9291     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_authconn;\r
9292     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_authconn;\r
9293     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_authconn;\r
9294     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_authconn;\r
9295     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_authconn;\r
9296     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_authconn;\r
9297     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_authconn;\r
9298     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_authconn;\r
9299     \r
9300     s->done_service_req = FALSE;\r
9301     s->we_are_in = s->userauth_success = FALSE;\r
9302     s->agent_response = NULL;\r
9303 #ifndef NO_GSSAPI\r
9304     s->tried_gssapi = FALSE;\r
9305 #endif\r
9307     if (!ssh->bare_connection) {\r
9308         if (!conf_get_int(ssh->conf, CONF_ssh_no_userauth)) {\r
9309             /*\r
9310              * Request userauth protocol, and await a response to it.\r
9311              */\r
9312             s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
9313             ssh2_pkt_addstring(s->pktout, "ssh-userauth");\r
9314             ssh2_pkt_send(ssh, s->pktout);\r
9315             crWaitUntilV(pktin);\r
9316             if (pktin->type == SSH2_MSG_SERVICE_ACCEPT)\r
9317                 s->done_service_req = TRUE;\r
9318         }\r
9319         if (!s->done_service_req) {\r
9320             /*\r
9321              * Request connection protocol directly, without authentication.\r
9322              */\r
9323             s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);\r
9324             ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
9325             ssh2_pkt_send(ssh, s->pktout);\r
9326             crWaitUntilV(pktin);\r
9327             if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {\r
9328                 s->we_are_in = TRUE; /* no auth required */\r
9329             } else {\r
9330                 bombout(("Server refused service request"));\r
9331                 crStopV;\r
9332             }\r
9333         }\r
9334     } else {\r
9335         s->we_are_in = TRUE;\r
9336     }\r
9338     /* Arrange to be able to deal with any BANNERs that come in.\r
9339      * (We do this now as packets may come in during the next bit.) */\r
9340     bufchain_init(&ssh->banner);\r
9341     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] =\r
9342         ssh2_msg_userauth_banner;\r
9344     /*\r
9345      * Misc one-time setup for authentication.\r
9346      */\r
9347     s->publickey_blob = NULL;\r
9348     if (!s->we_are_in) {\r
9350         /*\r
9351          * Load the public half of any configured public key file\r
9352          * for later use.\r
9353          */\r
9354         s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
9355         if (!filename_is_null(s->keyfile)) {\r
9356             int keytype;\r
9357             logeventf(ssh, "Reading key file \"%.150s\"",\r
9358                       filename_to_str(s->keyfile));\r
9359             keytype = key_type(s->keyfile);\r
9360             if (keytype == SSH_KEYTYPE_SSH2 ||\r
9361                 keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||\r
9362                 keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {\r
9363                 const char *error;\r
9364                 s->publickey_blob =\r
9365                     ssh2_userkey_loadpub(s->keyfile,\r
9366                                          &s->publickey_algorithm,\r
9367                                          &s->publickey_bloblen, \r
9368                                          &s->publickey_comment, &error);\r
9369                 if (s->publickey_blob) {\r
9370                     s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2);\r
9371                     if (!s->privatekey_available)\r
9372                         logeventf(ssh, "Key file contains public key only");\r
9373                     s->privatekey_encrypted =\r
9374                         ssh2_userkey_encrypted(s->keyfile, NULL);\r
9375                 } else {\r
9376                     char *msgbuf;\r
9377                     logeventf(ssh, "Unable to load key (%s)", \r
9378                               error);\r
9379                     msgbuf = dupprintf("Unable to load key file "\r
9380                                        "\"%.150s\" (%s)\r\n",\r
9381                                        filename_to_str(s->keyfile),\r
9382                                        error);\r
9383                     c_write_str(ssh, msgbuf);\r
9384                     sfree(msgbuf);\r
9385                 }\r
9386             } else {\r
9387                 char *msgbuf;\r
9388                 logeventf(ssh, "Unable to use this key file (%s)",\r
9389                           key_type_to_str(keytype));\r
9390                 msgbuf = dupprintf("Unable to use key file \"%.150s\""\r
9391                                    " (%s)\r\n",\r
9392                                    filename_to_str(s->keyfile),\r
9393                                    key_type_to_str(keytype));\r
9394                 c_write_str(ssh, msgbuf);\r
9395                 sfree(msgbuf);\r
9396                 s->publickey_blob = NULL;\r
9397             }\r
9398         }\r
9400         /*\r
9401          * Find out about any keys Pageant has (but if there's a\r
9402          * public key configured, filter out all others).\r
9403          */\r
9404         s->nkeys = 0;\r
9405         s->agent_response = NULL;\r
9406         s->pkblob_in_agent = NULL;\r
9407         if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists()) {\r
9409             void *r;\r
9411             logevent("Pageant is running. Requesting keys.");\r
9413             /* Request the keys held by the agent. */\r
9414             PUT_32BIT(s->agent_request, 1);\r
9415             s->agent_request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;\r
9416             ssh->auth_agent_query = agent_query(\r
9417                 s->agent_request, 5, &r, &s->agent_responselen,\r
9418                 ssh_agent_callback, ssh);\r
9419             if (ssh->auth_agent_query) {\r
9420                 do {\r
9421                     crReturnV;\r
9422                     if (pktin) {\r
9423                         bombout(("Unexpected data from server while"\r
9424                                  " waiting for agent response"));\r
9425                         crStopV;\r
9426                     }\r
9427                 } while (pktin || inlen > 0);\r
9428                 r = ssh->agent_response;\r
9429                 s->agent_responselen = ssh->agent_response_len;\r
9430             }\r
9431             s->agent_response = (unsigned char *) r;\r
9432             if (s->agent_response && s->agent_responselen >= 5 &&\r
9433                 s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {\r
9434                 int keyi;\r
9435                 unsigned char *p;\r
9436                 p = s->agent_response + 5;\r
9437                 s->nkeys = toint(GET_32BIT(p));\r
9439                 /*\r
9440                  * Vet the Pageant response to ensure that the key\r
9441                  * count and blob lengths make sense.\r
9442                  */\r
9443                 if (s->nkeys < 0) {\r
9444                     logeventf(ssh, "Pageant response contained a negative"\r
9445                               " key count %d", s->nkeys);\r
9446                     s->nkeys = 0;\r
9447                     goto done_agent_query;\r
9448                 } else {\r
9449                     unsigned char *q = p + 4;\r
9450                     int lenleft = s->agent_responselen - 5 - 4;\r
9452                     for (keyi = 0; keyi < s->nkeys; keyi++) {\r
9453                         int bloblen, commentlen;\r
9454                         if (lenleft < 4) {\r
9455                             logeventf(ssh, "Pageant response was truncated");\r
9456                             s->nkeys = 0;\r
9457                             goto done_agent_query;\r
9458                         }\r
9459                         bloblen = toint(GET_32BIT(q));\r
9460                         lenleft -= 4;\r
9461                         q += 4;\r
9462                         if (bloblen < 0 || bloblen > lenleft) {\r
9463                             logeventf(ssh, "Pageant response was truncated");\r
9464                             s->nkeys = 0;\r
9465                             goto done_agent_query;\r
9466                         }\r
9467                         lenleft -= bloblen;\r
9468                         q += bloblen;\r
9469                         commentlen = toint(GET_32BIT(q));\r
9470                         lenleft -= 4;\r
9471                         q += 4;\r
9472                         if (commentlen < 0 || commentlen > lenleft) {\r
9473                             logeventf(ssh, "Pageant response was truncated");\r
9474                             s->nkeys = 0;\r
9475                             goto done_agent_query;\r
9476                         }\r
9477                         lenleft -= commentlen;\r
9478                         q += commentlen;\r
9479                     }\r
9480                 }\r
9482                 p += 4;\r
9483                 logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys);\r
9484                 if (s->publickey_blob) {\r
9485                     /* See if configured key is in agent. */\r
9486                     for (keyi = 0; keyi < s->nkeys; keyi++) {\r
9487                         s->pklen = toint(GET_32BIT(p));\r
9488                         if (s->pklen == s->publickey_bloblen &&\r
9489                             !memcmp(p+4, s->publickey_blob,\r
9490                                     s->publickey_bloblen)) {\r
9491                             logeventf(ssh, "Pageant key #%d matches "\r
9492                                       "configured key file", keyi);\r
9493                             s->keyi = keyi;\r
9494                             s->pkblob_in_agent = p;\r
9495                             break;\r
9496                         }\r
9497                         p += 4 + s->pklen;\r
9498                         p += toint(GET_32BIT(p)) + 4; /* comment */\r
9499                     }\r
9500                     if (!s->pkblob_in_agent) {\r
9501                         logevent("Configured key file not in Pageant");\r
9502                         s->nkeys = 0;\r
9503                     }\r
9504                 }\r
9505             } else {\r
9506                 logevent("Failed to get reply from Pageant");\r
9507             }\r
9508           done_agent_query:;\r
9509         }\r
9511     }\r
9513     /*\r
9514      * We repeat this whole loop, including the username prompt,\r
9515      * until we manage a successful authentication. If the user\r
9516      * types the wrong _password_, they can be sent back to the\r
9517      * beginning to try another username, if this is configured on.\r
9518      * (If they specify a username in the config, they are never\r
9519      * asked, even if they do give a wrong password.)\r
9520      * \r
9521      * I think this best serves the needs of\r
9522      * \r
9523      *  - the people who have no configuration, no keys, and just\r
9524      *    want to try repeated (username,password) pairs until they\r
9525      *    type both correctly\r
9526      * \r
9527      *  - people who have keys and configuration but occasionally\r
9528      *    need to fall back to passwords\r
9529      * \r
9530      *  - people with a key held in Pageant, who might not have\r
9531      *    logged in to a particular machine before; so they want to\r
9532      *    type a username, and then _either_ their key will be\r
9533      *    accepted, _or_ they will type a password. If they mistype\r
9534      *    the username they will want to be able to get back and\r
9535      *    retype it!\r
9536      */\r
9537     s->got_username = FALSE;\r
9538     while (!s->we_are_in) {\r
9539         /*\r
9540          * Get a username.\r
9541          */\r
9542         if (s->got_username && !conf_get_int(ssh->conf, CONF_change_username)) {\r
9543             /*\r
9544              * We got a username last time round this loop, and\r
9545              * with change_username turned off we don't try to get\r
9546              * it again.\r
9547              */\r
9548         } else if ((ssh->username = get_remote_username(ssh->conf)) == NULL) {\r
9549             int ret; /* need not be kept over crReturn */\r
9550             s->cur_prompt = new_prompts(ssh->frontend);\r
9551             s->cur_prompt->to_server = TRUE;\r
9552             s->cur_prompt->name = dupstr("SSH login name");\r
9553             add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); \r
9554             ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
9555             while (ret < 0) {\r
9556                 ssh->send_ok = 1;\r
9557                 crWaitUntilV(!pktin);\r
9558                 ret = get_userpass_input(s->cur_prompt, in, inlen);\r
9559                 ssh->send_ok = 0;\r
9560             }\r
9561             if (!ret) {\r
9562                 /*\r
9563                  * get_userpass_input() failed to get a username.\r
9564                  * Terminate.\r
9565                  */\r
9566                 free_prompts(s->cur_prompt);\r
9567                 ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);\r
9568                 crStopV;\r
9569             }\r
9570             ssh->username = dupstr(s->cur_prompt->prompts[0]->result);\r
9571             free_prompts(s->cur_prompt);\r
9572         } else {\r
9573             char *stuff;\r
9574             if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {\r
9575                 stuff = dupprintf("Using username \"%s\".\r\n", ssh->username);\r
9576                 c_write_str(ssh, stuff);\r
9577                 sfree(stuff);\r
9578             }\r
9579         }\r
9580         s->got_username = TRUE;\r
9582         /*\r
9583          * Send an authentication request using method "none": (a)\r
9584          * just in case it succeeds, and (b) so that we know what\r
9585          * authentication methods we can usefully try next.\r
9586          */\r
9587         ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
9589         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
9590         ssh2_pkt_addstring(s->pktout, ssh->username);\r
9591         ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */\r
9592         ssh2_pkt_addstring(s->pktout, "none");    /* method */\r
9593         ssh2_pkt_send(ssh, s->pktout);\r
9594         s->type = AUTH_TYPE_NONE;\r
9595         s->gotit = FALSE;\r
9596         s->we_are_in = FALSE;\r
9598         s->tried_pubkey_config = FALSE;\r
9599         s->kbd_inter_refused = FALSE;\r
9601         /* Reset agent request state. */\r
9602         s->done_agent = FALSE;\r
9603         if (s->agent_response) {\r
9604             if (s->pkblob_in_agent) {\r
9605                 s->agentp = s->pkblob_in_agent;\r
9606             } else {\r
9607                 s->agentp = s->agent_response + 5 + 4;\r
9608                 s->keyi = 0;\r
9609             }\r
9610         }\r
9612         while (1) {\r
9613             char *methods = NULL;\r
9614             int methlen = 0;\r
9616             /*\r
9617              * Wait for the result of the last authentication request.\r
9618              */\r
9619             if (!s->gotit)\r
9620                 crWaitUntilV(pktin);\r
9621             /*\r
9622              * Now is a convenient point to spew any banner material\r
9623              * that we've accumulated. (This should ensure that when\r
9624              * we exit the auth loop, we haven't any left to deal\r
9625              * with.)\r
9626              */\r
9627             {\r
9628                 int size = bufchain_size(&ssh->banner);\r
9629                 /*\r
9630                  * Don't show the banner if we're operating in\r
9631                  * non-verbose non-interactive mode. (It's probably\r
9632                  * a script, which means nobody will read the\r
9633                  * banner _anyway_, and moreover the printing of\r
9634                  * the banner will screw up processing on the\r
9635                  * output of (say) plink.)\r
9636                  */\r
9637                 if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {\r
9638                     char *banner = snewn(size, char);\r
9639                     bufchain_fetch(&ssh->banner, banner, size);\r
9640                     c_write_untrusted(ssh, banner, size);\r
9641                     sfree(banner);\r
9642                 }\r
9643                 bufchain_clear(&ssh->banner);\r
9644             }\r
9645             if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {\r
9646                 logevent("Access granted");\r
9647                 s->we_are_in = s->userauth_success = TRUE;\r
9648                 break;\r
9649             }\r
9651             if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) {\r
9652                 bombout(("Strange packet received during authentication: "\r
9653                          "type %d", pktin->type));\r
9654                 crStopV;\r
9655             }\r
9657             s->gotit = FALSE;\r
9659             /*\r
9660              * OK, we're now sitting on a USERAUTH_FAILURE message, so\r
9661              * we can look at the string in it and know what we can\r
9662              * helpfully try next.\r
9663              */\r
9664             if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {\r
9665                 ssh_pkt_getstring(pktin, &methods, &methlen);\r
9666                 if (!ssh2_pkt_getbool(pktin)) {\r
9667                     /*\r
9668                      * We have received an unequivocal Access\r
9669                      * Denied. This can translate to a variety of\r
9670                      * messages, or no message at all.\r
9671                      *\r
9672                      * For forms of authentication which are attempted\r
9673                      * implicitly, by which I mean without printing\r
9674                      * anything in the window indicating that we're\r
9675                      * trying them, we should never print 'Access\r
9676                      * denied'.\r
9677                      *\r
9678                      * If we do print a message saying that we're\r
9679                      * attempting some kind of authentication, it's OK\r
9680                      * to print a followup message saying it failed -\r
9681                      * but the message may sometimes be more specific\r
9682                      * than simply 'Access denied'.\r
9683                      *\r
9684                      * Additionally, if we'd just tried password\r
9685                      * authentication, we should break out of this\r
9686                      * whole loop so as to go back to the username\r
9687                      * prompt (iff we're configured to allow\r
9688                      * username change attempts).\r
9689                      */\r
9690                     if (s->type == AUTH_TYPE_NONE) {\r
9691                         /* do nothing */\r
9692                     } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||\r
9693                                s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {\r
9694                         if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)\r
9695                             c_write_str(ssh, "Server refused our key\r\n");\r
9696                         logevent("Server refused our key");\r
9697                     } else if (s->type == AUTH_TYPE_PUBLICKEY) {\r
9698                         /* This _shouldn't_ happen except by a\r
9699                          * protocol bug causing client and server to\r
9700                          * disagree on what is a correct signature. */\r
9701                         c_write_str(ssh, "Server refused public-key signature"\r
9702                                     " despite accepting key!\r\n");\r
9703                         logevent("Server refused public-key signature"\r
9704                                  " despite accepting key!");\r
9705                     } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {\r
9706                         /* quiet, so no c_write */\r
9707                         logevent("Server refused keyboard-interactive authentication");\r
9708                     } else if (s->type==AUTH_TYPE_GSSAPI) {\r
9709                         /* always quiet, so no c_write */\r
9710                         /* also, the code down in the GSSAPI block has\r
9711                          * already logged this in the Event Log */\r
9712                     } else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) {\r
9713                         logevent("Keyboard-interactive authentication failed");\r
9714                         c_write_str(ssh, "Access denied\r\n");\r
9715                     } else {\r
9716                         assert(s->type == AUTH_TYPE_PASSWORD);\r
9717                         logevent("Password authentication failed");\r
9718                         c_write_str(ssh, "Access denied\r\n");\r
9720                         if (conf_get_int(ssh->conf, CONF_change_username)) {\r
9721                             /* XXX perhaps we should allow\r
9722                              * keyboard-interactive to do this too? */\r
9723                             s->we_are_in = FALSE;\r
9724                             break;\r
9725                         }\r
9726                     }\r
9727                 } else {\r
9728                     c_write_str(ssh, "Further authentication required\r\n");\r
9729                     logevent("Further authentication required");\r
9730                 }\r
9732                 s->can_pubkey =\r
9733                     in_commasep_string("publickey", methods, methlen);\r
9734                 s->can_passwd =\r
9735                     in_commasep_string("password", methods, methlen);\r
9736                 s->can_keyb_inter = conf_get_int(ssh->conf, CONF_try_ki_auth) &&\r
9737                     in_commasep_string("keyboard-interactive", methods, methlen);\r
9738 #ifndef NO_GSSAPI\r
9739                 if (conf_get_int(ssh->conf, CONF_try_gssapi_auth) &&\r
9740                     in_commasep_string("gssapi-with-mic", methods, methlen)) {\r
9741                     /* Try loading the GSS libraries and see if we\r
9742                      * have any. */\r
9743                     if (!ssh->gsslibs)\r
9744                         ssh->gsslibs = ssh_gss_setup(ssh->conf);\r
9745                     s->can_gssapi = (ssh->gsslibs->nlibraries > 0);\r
9746                 } else {\r
9747                     /* No point in even bothering to try to load the\r
9748                      * GSS libraries, if the user configuration and\r
9749                      * server aren't both prepared to attempt GSSAPI\r
9750                      * auth in the first place. */\r
9751                     s->can_gssapi = FALSE;\r
9752                 }\r
9753 #endif\r
9754             }\r
9756             ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
9758             if (s->can_pubkey && !s->done_agent && s->nkeys) {\r
9760                 /*\r
9761                  * Attempt public-key authentication using a key from Pageant.\r
9762                  */\r
9764                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
9766                 logeventf(ssh, "Trying Pageant key #%d", s->keyi);\r
9768                 /* Unpack key from agent response */\r
9769                 s->pklen = toint(GET_32BIT(s->agentp));\r
9770                 s->agentp += 4;\r
9771                 s->pkblob = (char *)s->agentp;\r
9772                 s->agentp += s->pklen;\r
9773                 s->alglen = toint(GET_32BIT(s->pkblob));\r
9774                 s->alg = s->pkblob + 4;\r
9775                 s->commentlen = toint(GET_32BIT(s->agentp));\r
9776                 s->agentp += 4;\r
9777                 s->commentp = (char *)s->agentp;\r
9778                 s->agentp += s->commentlen;\r
9779                 /* s->agentp now points at next key, if any */\r
9781                 /* See if server will accept it */\r
9782                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
9783                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
9784                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
9785                                                     /* service requested */\r
9786                 ssh2_pkt_addstring(s->pktout, "publickey");\r
9787                                                     /* method */\r
9788                 ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */\r
9789                 ssh2_pkt_addstring_start(s->pktout);\r
9790                 ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
9791                 ssh2_pkt_addstring_start(s->pktout);\r
9792                 ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
9793                 ssh2_pkt_send(ssh, s->pktout);\r
9794                 s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;\r
9796                 crWaitUntilV(pktin);\r
9797                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
9799                     /* Offer of key refused. */\r
9800                     s->gotit = TRUE;\r
9802                 } else {\r
9803                     \r
9804                     void *vret;\r
9806                     if (flags & FLAG_VERBOSE) {\r
9807                         c_write_str(ssh, "Authenticating with "\r
9808                                     "public key \"");\r
9809                         c_write(ssh, s->commentp, s->commentlen);\r
9810                         c_write_str(ssh, "\" from agent\r\n");\r
9811                     }\r
9813                     /*\r
9814                      * Server is willing to accept the key.\r
9815                      * Construct a SIGN_REQUEST.\r
9816                      */\r
9817                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
9818                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
9819                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
9820                                                         /* service requested */\r
9821                     ssh2_pkt_addstring(s->pktout, "publickey");\r
9822                                                         /* method */\r
9823                     ssh2_pkt_addbool(s->pktout, TRUE);  /* signature included */\r
9824                     ssh2_pkt_addstring_start(s->pktout);\r
9825                     ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);\r
9826                     ssh2_pkt_addstring_start(s->pktout);\r
9827                     ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);\r
9829                     /* Ask agent for signature. */\r
9830                     s->siglen = s->pktout->length - 5 + 4 +\r
9831                         ssh->v2_session_id_len;\r
9832                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
9833                         s->siglen -= 4;\r
9834                     s->len = 1;       /* message type */\r
9835                     s->len += 4 + s->pklen;     /* key blob */\r
9836                     s->len += 4 + s->siglen;    /* data to sign */\r
9837                     s->len += 4;      /* flags */\r
9838                     s->agentreq = snewn(4 + s->len, char);\r
9839                     PUT_32BIT(s->agentreq, s->len);\r
9840                     s->q = s->agentreq + 4;\r
9841                     *s->q++ = SSH2_AGENTC_SIGN_REQUEST;\r
9842                     PUT_32BIT(s->q, s->pklen);\r
9843                     s->q += 4;\r
9844                     memcpy(s->q, s->pkblob, s->pklen);\r
9845                     s->q += s->pklen;\r
9846                     PUT_32BIT(s->q, s->siglen);\r
9847                     s->q += 4;\r
9848                     /* Now the data to be signed... */\r
9849                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
9850                         PUT_32BIT(s->q, ssh->v2_session_id_len);\r
9851                         s->q += 4;\r
9852                     }\r
9853                     memcpy(s->q, ssh->v2_session_id,\r
9854                            ssh->v2_session_id_len);\r
9855                     s->q += ssh->v2_session_id_len;\r
9856                     memcpy(s->q, s->pktout->data + 5,\r
9857                            s->pktout->length - 5);\r
9858                     s->q += s->pktout->length - 5;\r
9859                     /* And finally the (zero) flags word. */\r
9860                     PUT_32BIT(s->q, 0);\r
9861                     ssh->auth_agent_query = agent_query(\r
9862                         s->agentreq, s->len + 4, &vret, &s->retlen,\r
9863                         ssh_agent_callback, ssh);\r
9864                     if (ssh->auth_agent_query) {\r
9865                         do {\r
9866                             crReturnV;\r
9867                             if (pktin) {\r
9868                                 bombout(("Unexpected data from server"\r
9869                                          " while waiting for agent"\r
9870                                          " response"));\r
9871                                 crStopV;\r
9872                             }\r
9873                         } while (pktin || inlen > 0);\r
9874                         vret = ssh->agent_response;\r
9875                         s->retlen = ssh->agent_response_len;\r
9876                     }\r
9877                     s->ret = vret;\r
9878                     sfree(s->agentreq);\r
9879                     if (s->ret) {\r
9880                         if (s->retlen >= 9 &&\r
9881                             s->ret[4] == SSH2_AGENT_SIGN_RESPONSE &&\r
9882                             GET_32BIT(s->ret + 5) <= (unsigned)(s->retlen-9)) {\r
9883                             logevent("Sending Pageant's response");\r
9884                             ssh2_add_sigblob(ssh, s->pktout,\r
9885                                              s->pkblob, s->pklen,\r
9886                                              s->ret + 9,\r
9887                                              GET_32BIT(s->ret + 5));\r
9888                             ssh2_pkt_send(ssh, s->pktout);\r
9889                             s->type = AUTH_TYPE_PUBLICKEY;\r
9890                         } else {\r
9891                             /* FIXME: less drastic response */\r
9892                             bombout(("Pageant failed to answer challenge"));\r
9893                             crStopV;\r
9894                         }\r
9895                     }\r
9896                 }\r
9898                 /* Do we have any keys left to try? */\r
9899                 if (s->pkblob_in_agent) {\r
9900                     s->done_agent = TRUE;\r
9901                     s->tried_pubkey_config = TRUE;\r
9902                 } else {\r
9903                     s->keyi++;\r
9904                     if (s->keyi >= s->nkeys)\r
9905                         s->done_agent = TRUE;\r
9906                 }\r
9908             } else if (s->can_pubkey && s->publickey_blob &&\r
9909                        s->privatekey_available && !s->tried_pubkey_config) {\r
9911                 struct ssh2_userkey *key;   /* not live over crReturn */\r
9912                 char *passphrase;           /* not live over crReturn */\r
9914                 ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;\r
9916                 s->tried_pubkey_config = TRUE;\r
9918                 /*\r
9919                  * Try the public key supplied in the configuration.\r
9920                  *\r
9921                  * First, offer the public blob to see if the server is\r
9922                  * willing to accept it.\r
9923                  */\r
9924                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
9925                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
9926                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
9927                                                 /* service requested */\r
9928                 ssh2_pkt_addstring(s->pktout, "publickey");     /* method */\r
9929                 ssh2_pkt_addbool(s->pktout, FALSE);\r
9930                                                 /* no signature included */\r
9931                 ssh2_pkt_addstring(s->pktout, s->publickey_algorithm);\r
9932                 ssh2_pkt_addstring_start(s->pktout);\r
9933                 ssh2_pkt_addstring_data(s->pktout,\r
9934                                         (char *)s->publickey_blob,\r
9935                                         s->publickey_bloblen);\r
9936                 ssh2_pkt_send(ssh, s->pktout);\r
9937                 logevent("Offered public key");\r
9939                 crWaitUntilV(pktin);\r
9940                 if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {\r
9941                     /* Key refused. Give up. */\r
9942                     s->gotit = TRUE; /* reconsider message next loop */\r
9943                     s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;\r
9944                     continue; /* process this new message */\r
9945                 }\r
9946                 logevent("Offer of public key accepted");\r
9948                 /*\r
9949                  * Actually attempt a serious authentication using\r
9950                  * the key.\r
9951                  */\r
9952                 if (flags & FLAG_VERBOSE) {\r
9953                     c_write_str(ssh, "Authenticating with public key \"");\r
9954                     c_write_str(ssh, s->publickey_comment);\r
9955                     c_write_str(ssh, "\"\r\n");\r
9956                 }\r
9957                 key = NULL;\r
9958                 while (!key) {\r
9959                     const char *error;  /* not live over crReturn */\r
9960                     if (s->privatekey_encrypted) {\r
9961                         /*\r
9962                          * Get a passphrase from the user.\r
9963                          */\r
9964                         int ret; /* need not be kept over crReturn */\r
9965                         s->cur_prompt = new_prompts(ssh->frontend);\r
9966                         s->cur_prompt->to_server = FALSE;\r
9967                         s->cur_prompt->name = dupstr("SSH key passphrase");\r
9968                         add_prompt(s->cur_prompt,\r
9969                                    dupprintf("Passphrase for key \"%.100s\": ",\r
9970                                              s->publickey_comment),\r
9971                                    FALSE);\r
9972                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
9973                         while (ret < 0) {\r
9974                             ssh->send_ok = 1;\r
9975                             crWaitUntilV(!pktin);\r
9976                             ret = get_userpass_input(s->cur_prompt,\r
9977                                                      in, inlen);\r
9978                             ssh->send_ok = 0;\r
9979                         }\r
9980                         if (!ret) {\r
9981                             /* Failed to get a passphrase. Terminate. */\r
9982                             free_prompts(s->cur_prompt);\r
9983                             ssh_disconnect(ssh, NULL,\r
9984                                            "Unable to authenticate",\r
9985                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
9986                                            TRUE);\r
9987                             crStopV;\r
9988                         }\r
9989                         passphrase =\r
9990                             dupstr(s->cur_prompt->prompts[0]->result);\r
9991                         free_prompts(s->cur_prompt);\r
9992                     } else {\r
9993                         passphrase = NULL; /* no passphrase needed */\r
9994                     }\r
9996                     /*\r
9997                      * Try decrypting the key.\r
9998                      */\r
9999                     s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);\r
10000                     key = ssh2_load_userkey(s->keyfile, passphrase, &error);\r
10001                     if (passphrase) {\r
10002                         /* burn the evidence */\r
10003                         smemclr(passphrase, strlen(passphrase));\r
10004                         sfree(passphrase);\r
10005                     }\r
10006                     if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {\r
10007                         if (passphrase &&\r
10008                             (key == SSH2_WRONG_PASSPHRASE)) {\r
10009                             c_write_str(ssh, "Wrong passphrase\r\n");\r
10010                             key = NULL;\r
10011                             /* and loop again */\r
10012                         } else {\r
10013                             c_write_str(ssh, "Unable to load private key (");\r
10014                             c_write_str(ssh, error);\r
10015                             c_write_str(ssh, ")\r\n");\r
10016                             key = NULL;\r
10017                             break; /* try something else */\r
10018                         }\r
10019                     }\r
10020                 }\r
10022                 if (key) {\r
10023                     unsigned char *pkblob, *sigblob, *sigdata;\r
10024                     int pkblob_len, sigblob_len, sigdata_len;\r
10025                     int p;\r
10027                     /*\r
10028                      * We have loaded the private key and the server\r
10029                      * has announced that it's willing to accept it.\r
10030                      * Hallelujah. Generate a signature and send it.\r
10031                      */\r
10032                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
10033                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
10034                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
10035                                                     /* service requested */\r
10036                     ssh2_pkt_addstring(s->pktout, "publickey");\r
10037                                                     /* method */\r
10038                     ssh2_pkt_addbool(s->pktout, TRUE);\r
10039                                                     /* signature follows */\r
10040                     ssh2_pkt_addstring(s->pktout, key->alg->name);\r
10041                     pkblob = key->alg->public_blob(key->data,\r
10042                                                    &pkblob_len);\r
10043                     ssh2_pkt_addstring_start(s->pktout);\r
10044                     ssh2_pkt_addstring_data(s->pktout, (char *)pkblob,\r
10045                                             pkblob_len);\r
10047                     /*\r
10048                      * The data to be signed is:\r
10049                      *\r
10050                      *   string  session-id\r
10051                      *\r
10052                      * followed by everything so far placed in the\r
10053                      * outgoing packet.\r
10054                      */\r
10055                     sigdata_len = s->pktout->length - 5 + 4 +\r
10056                         ssh->v2_session_id_len;\r
10057                     if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)\r
10058                         sigdata_len -= 4;\r
10059                     sigdata = snewn(sigdata_len, unsigned char);\r
10060                     p = 0;\r
10061                     if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {\r
10062                         PUT_32BIT(sigdata+p, ssh->v2_session_id_len);\r
10063                         p += 4;\r
10064                     }\r
10065                     memcpy(sigdata+p, ssh->v2_session_id,\r
10066                            ssh->v2_session_id_len);\r
10067                     p += ssh->v2_session_id_len;\r
10068                     memcpy(sigdata+p, s->pktout->data + 5,\r
10069                            s->pktout->length - 5);\r
10070                     p += s->pktout->length - 5;\r
10071                     assert(p == sigdata_len);\r
10072                     sigblob = key->alg->sign(key->data, (char *)sigdata,\r
10073                                              sigdata_len, &sigblob_len);\r
10074                     ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,\r
10075                                      sigblob, sigblob_len);\r
10076                     sfree(pkblob);\r
10077                     sfree(sigblob);\r
10078                     sfree(sigdata);\r
10080                     ssh2_pkt_send(ssh, s->pktout);\r
10081                     logevent("Sent public key signature");\r
10082                     s->type = AUTH_TYPE_PUBLICKEY;\r
10083                     key->alg->freekey(key->data);\r
10084                     sfree(key->comment);\r
10085                     sfree(key);\r
10086                 }\r
10088 #ifndef NO_GSSAPI\r
10089             } else if (s->can_gssapi && !s->tried_gssapi) {\r
10091                 /* GSSAPI Authentication */\r
10093                 int micoffset, len;\r
10094                 char *data;\r
10095                 Ssh_gss_buf mic;\r
10096                 s->type = AUTH_TYPE_GSSAPI;\r
10097                 s->tried_gssapi = TRUE;\r
10098                 s->gotit = TRUE;\r
10099                 ssh->pkt_actx = SSH2_PKTCTX_GSSAPI;\r
10101                 /*\r
10102                  * Pick the highest GSS library on the preference\r
10103                  * list.\r
10104                  */\r
10105                 {\r
10106                     int i, j;\r
10107                     s->gsslib = NULL;\r
10108                     for (i = 0; i < ngsslibs; i++) {\r
10109                         int want_id = conf_get_int_int(ssh->conf,\r
10110                                                        CONF_ssh_gsslist, i);\r
10111                         for (j = 0; j < ssh->gsslibs->nlibraries; j++)\r
10112                             if (ssh->gsslibs->libraries[j].id == want_id) {\r
10113                                 s->gsslib = &ssh->gsslibs->libraries[j];\r
10114                                 goto got_gsslib;   /* double break */\r
10115                             }\r
10116                     }\r
10117                     got_gsslib:\r
10118                     /*\r
10119                      * We always expect to have found something in\r
10120                      * the above loop: we only came here if there\r
10121                      * was at least one viable GSS library, and the\r
10122                      * preference list should always mention\r
10123                      * everything and only change the order.\r
10124                      */\r
10125                     assert(s->gsslib);\r
10126                 }\r
10128                 if (s->gsslib->gsslogmsg)\r
10129                     logevent(s->gsslib->gsslogmsg);\r
10131                 /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */\r
10132                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
10133                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
10134                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
10135                 ssh2_pkt_addstring(s->pktout, "gssapi-with-mic");\r
10136                 logevent("Attempting GSSAPI authentication");\r
10138                 /* add mechanism info */\r
10139                 s->gsslib->indicate_mech(s->gsslib, &s->gss_buf);\r
10141                 /* number of GSSAPI mechanisms */\r
10142                 ssh2_pkt_adduint32(s->pktout,1);\r
10144                 /* length of OID + 2 */\r
10145                 ssh2_pkt_adduint32(s->pktout, s->gss_buf.length + 2);\r
10146                 ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);\r
10148                 /* length of OID */\r
10149                 ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.length);\r
10151                 ssh_pkt_adddata(s->pktout, s->gss_buf.value,\r
10152                                 s->gss_buf.length);\r
10153                 ssh2_pkt_send(ssh, s->pktout);\r
10154                 crWaitUntilV(pktin);\r
10155                 if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {\r
10156                     logevent("GSSAPI authentication request refused");\r
10157                     continue;\r
10158                 }\r
10160                 /* check returned packet ... */\r
10162                 ssh_pkt_getstring(pktin, &data, &len);\r
10163                 s->gss_rcvtok.value = data;\r
10164                 s->gss_rcvtok.length = len;\r
10165                 if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||\r
10166                     ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||\r
10167                     ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||\r
10168                     memcmp((char *)s->gss_rcvtok.value + 2,\r
10169                            s->gss_buf.value,s->gss_buf.length) ) {\r
10170                     logevent("GSSAPI authentication - wrong response from server");\r
10171                     continue;\r
10172                 }\r
10174                 /* now start running */\r
10175                 s->gss_stat = s->gsslib->import_name(s->gsslib,\r
10176                                                      ssh->fullhostname,\r
10177                                                      &s->gss_srv_name);\r
10178                 if (s->gss_stat != SSH_GSS_OK) {\r
10179                     if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)\r
10180                         logevent("GSSAPI import name failed - Bad service name");\r
10181                     else\r
10182                         logevent("GSSAPI import name failed");\r
10183                     continue;\r
10184                 }\r
10186                 /* fetch TGT into GSS engine */\r
10187                 s->gss_stat = s->gsslib->acquire_cred(s->gsslib, &s->gss_ctx);\r
10189                 if (s->gss_stat != SSH_GSS_OK) {\r
10190                     logevent("GSSAPI authentication failed to get credentials");\r
10191                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
10192                     continue;\r
10193                 }\r
10195                 /* initial tokens are empty */\r
10196                 SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);\r
10197                 SSH_GSS_CLEAR_BUF(&s->gss_sndtok);\r
10199                 /* now enter the loop */\r
10200                 do {\r
10201                     s->gss_stat = s->gsslib->init_sec_context\r
10202                         (s->gsslib,\r
10203                          &s->gss_ctx,\r
10204                          s->gss_srv_name,\r
10205                          conf_get_int(ssh->conf, CONF_gssapifwd),\r
10206                          &s->gss_rcvtok,\r
10207                          &s->gss_sndtok);\r
10209                     if (s->gss_stat!=SSH_GSS_S_COMPLETE &&\r
10210                         s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) {\r
10211                         logevent("GSSAPI authentication initialisation failed");\r
10213                         if (s->gsslib->display_status(s->gsslib, s->gss_ctx,\r
10214                                                       &s->gss_buf) == SSH_GSS_OK) {\r
10215                             logevent(s->gss_buf.value);\r
10216                             sfree(s->gss_buf.value);\r
10217                         }\r
10219                         break;\r
10220                     }\r
10221                     logevent("GSSAPI authentication initialised");\r
10223                     /* Client and server now exchange tokens until GSSAPI\r
10224                      * no longer says CONTINUE_NEEDED */\r
10226                     if (s->gss_sndtok.length != 0) {\r
10227                         s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);\r
10228                         ssh_pkt_addstring_start(s->pktout);\r
10229                         ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.value,s->gss_sndtok.length);\r
10230                         ssh2_pkt_send(ssh, s->pktout);\r
10231                         s->gsslib->free_tok(s->gsslib, &s->gss_sndtok);\r
10232                     }\r
10234                     if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {\r
10235                         crWaitUntilV(pktin);\r
10236                         if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {\r
10237                             logevent("GSSAPI authentication - bad server response");\r
10238                             s->gss_stat = SSH_GSS_FAILURE;\r
10239                             break;\r
10240                         }\r
10241                         ssh_pkt_getstring(pktin, &data, &len);\r
10242                         s->gss_rcvtok.value = data;\r
10243                         s->gss_rcvtok.length = len;\r
10244                     }\r
10245                 } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);\r
10247                 if (s->gss_stat != SSH_GSS_OK) {\r
10248                     s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
10249                     s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
10250                     continue;\r
10251                 }\r
10252                 logevent("GSSAPI authentication loop finished OK");\r
10254                 /* Now send the MIC */\r
10256                 s->pktout = ssh2_pkt_init(0);\r
10257                 micoffset = s->pktout->length;\r
10258                 ssh_pkt_addstring_start(s->pktout);\r
10259                 ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len);\r
10260                 ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST);\r
10261                 ssh_pkt_addstring(s->pktout, ssh->username);\r
10262                 ssh_pkt_addstring(s->pktout, "ssh-connection");\r
10263                 ssh_pkt_addstring(s->pktout, "gssapi-with-mic");\r
10265                 s->gss_buf.value = (char *)s->pktout->data + micoffset;\r
10266                 s->gss_buf.length = s->pktout->length - micoffset;\r
10268                 s->gsslib->get_mic(s->gsslib, s->gss_ctx, &s->gss_buf, &mic);\r
10269                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC);\r
10270                 ssh_pkt_addstring_start(s->pktout);\r
10271                 ssh_pkt_addstring_data(s->pktout, mic.value, mic.length);\r
10272                 ssh2_pkt_send(ssh, s->pktout);\r
10273                 s->gsslib->free_mic(s->gsslib, &mic);\r
10275                 s->gotit = FALSE;\r
10277                 s->gsslib->release_name(s->gsslib, &s->gss_srv_name);\r
10278                 s->gsslib->release_cred(s->gsslib, &s->gss_ctx);\r
10279                 continue;\r
10280 #endif\r
10281             } else if (s->can_keyb_inter && !s->kbd_inter_refused) {\r
10283                 /*\r
10284                  * Keyboard-interactive authentication.\r
10285                  */\r
10287                 s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;\r
10289                 ssh->pkt_actx = SSH2_PKTCTX_KBDINTER;\r
10291                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
10292                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
10293                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
10294                                                         /* service requested */\r
10295                 ssh2_pkt_addstring(s->pktout, "keyboard-interactive");\r
10296                                                         /* method */\r
10297                 ssh2_pkt_addstring(s->pktout, "");      /* lang */\r
10298                 ssh2_pkt_addstring(s->pktout, "");      /* submethods */\r
10299                 ssh2_pkt_send(ssh, s->pktout);\r
10300                 \r
10301                 logevent("Attempting keyboard-interactive authentication");\r
10303                 crWaitUntilV(pktin);\r
10304                 if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
10305                     /* Server is not willing to do keyboard-interactive\r
10306                      * at all (or, bizarrely but legally, accepts the\r
10307                      * user without actually issuing any prompts).\r
10308                      * Give up on it entirely. */\r
10309                     s->gotit = TRUE;\r
10310                     s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;\r
10311                     s->kbd_inter_refused = TRUE; /* don't try it again */\r
10312                     continue;\r
10313                 }\r
10315                 /*\r
10316                  * Loop while the server continues to send INFO_REQUESTs.\r
10317                  */\r
10318                 while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {\r
10320                     char *name, *inst, *lang;\r
10321                     int name_len, inst_len, lang_len;\r
10322                     int i;\r
10324                     /*\r
10325                      * We've got a fresh USERAUTH_INFO_REQUEST.\r
10326                      * Get the preamble and start building a prompt.\r
10327                      */\r
10328                     ssh_pkt_getstring(pktin, &name, &name_len);\r
10329                     ssh_pkt_getstring(pktin, &inst, &inst_len);\r
10330                     ssh_pkt_getstring(pktin, &lang, &lang_len);\r
10331                     s->cur_prompt = new_prompts(ssh->frontend);\r
10332                     s->cur_prompt->to_server = TRUE;\r
10334                     /*\r
10335                      * Get any prompt(s) from the packet.\r
10336                      */\r
10337                     s->num_prompts = ssh_pkt_getuint32(pktin);\r
10338                     for (i = 0; i < s->num_prompts; i++) {\r
10339                         char *prompt;\r
10340                         int prompt_len;\r
10341                         int echo;\r
10342                         static char noprompt[] =\r
10343                             "<server failed to send prompt>: ";\r
10345                         ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
10346                         echo = ssh2_pkt_getbool(pktin);\r
10347                         if (!prompt_len) {\r
10348                             prompt = noprompt;\r
10349                             prompt_len = lenof(noprompt)-1;\r
10350                         }\r
10351                         add_prompt(s->cur_prompt,\r
10352                                    dupprintf("%.*s", prompt_len, prompt),\r
10353                                    echo);\r
10354                     }\r
10356                     if (name_len) {\r
10357                         /* FIXME: better prefix to distinguish from\r
10358                          * local prompts? */\r
10359                         s->cur_prompt->name =\r
10360                             dupprintf("SSH server: %.*s", name_len, name);\r
10361                         s->cur_prompt->name_reqd = TRUE;\r
10362                     } else {\r
10363                         s->cur_prompt->name =\r
10364                             dupstr("SSH server authentication");\r
10365                         s->cur_prompt->name_reqd = FALSE;\r
10366                     }\r
10367                     /* We add a prefix to try to make it clear that a prompt\r
10368                      * has come from the server.\r
10369                      * FIXME: ugly to print "Using..." in prompt _every_\r
10370                      * time round. Can this be done more subtly? */\r
10371                     /* Special case: for reasons best known to themselves,\r
10372                      * some servers send k-i requests with no prompts and\r
10373                      * nothing to display. Keep quiet in this case. */\r
10374                     if (s->num_prompts || name_len || inst_len) {\r
10375                         s->cur_prompt->instruction =\r
10376                             dupprintf("Using keyboard-interactive authentication.%s%.*s",\r
10377                                       inst_len ? "\n" : "", inst_len, inst);\r
10378                         s->cur_prompt->instr_reqd = TRUE;\r
10379                     } else {\r
10380                         s->cur_prompt->instr_reqd = FALSE;\r
10381                     }\r
10383                     /*\r
10384                      * Display any instructions, and get the user's\r
10385                      * response(s).\r
10386                      */\r
10387                     {\r
10388                         int ret; /* not live over crReturn */\r
10389                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
10390                         while (ret < 0) {\r
10391                             ssh->send_ok = 1;\r
10392                             crWaitUntilV(!pktin);\r
10393                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
10394                             ssh->send_ok = 0;\r
10395                         }\r
10396                         if (!ret) {\r
10397                             /*\r
10398                              * Failed to get responses. Terminate.\r
10399                              */\r
10400                             free_prompts(s->cur_prompt);\r
10401                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
10402                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
10403                                            TRUE);\r
10404                             crStopV;\r
10405                         }\r
10406                     }\r
10408                     /*\r
10409                      * Send the response(s) to the server.\r
10410                      */\r
10411                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);\r
10412                     ssh2_pkt_adduint32(s->pktout, s->num_prompts);\r
10413                     for (i=0; i < s->num_prompts; i++) {\r
10414                         ssh2_pkt_addstring(s->pktout,\r
10415                                            s->cur_prompt->prompts[i]->result);\r
10416                     }\r
10417                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
10419                     /*\r
10420                      * Free the prompts structure from this iteration.\r
10421                      * If there's another, a new one will be allocated\r
10422                      * when we return to the top of this while loop.\r
10423                      */\r
10424                     free_prompts(s->cur_prompt);\r
10426                     /*\r
10427                      * Get the next packet in case it's another\r
10428                      * INFO_REQUEST.\r
10429                      */\r
10430                     crWaitUntilV(pktin);\r
10432                 }\r
10434                 /*\r
10435                  * We should have SUCCESS or FAILURE now.\r
10436                  */\r
10437                 s->gotit = TRUE;\r
10439             } else if (s->can_passwd) {\r
10441                 /*\r
10442                  * Plain old password authentication.\r
10443                  */\r
10444                 int ret; /* not live over crReturn */\r
10445                 int changereq_first_time; /* not live over crReturn */\r
10447                 ssh->pkt_actx = SSH2_PKTCTX_PASSWORD;\r
10449                 s->cur_prompt = new_prompts(ssh->frontend);\r
10450                 s->cur_prompt->to_server = TRUE;\r
10451                 s->cur_prompt->name = dupstr("SSH password");\r
10452                 add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",\r
10453                                                     ssh->username,\r
10454                                                     ssh->savedhost),\r
10455                            FALSE);\r
10457                 ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
10458                 while (ret < 0) {\r
10459                     ssh->send_ok = 1;\r
10460                     crWaitUntilV(!pktin);\r
10461                     ret = get_userpass_input(s->cur_prompt, in, inlen);\r
10462                     ssh->send_ok = 0;\r
10463                 }\r
10464                 if (!ret) {\r
10465                     /*\r
10466                      * Failed to get responses. Terminate.\r
10467                      */\r
10468                     free_prompts(s->cur_prompt);\r
10469                     ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
10470                                    SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
10471                                    TRUE);\r
10472                     crStopV;\r
10473                 }\r
10474                 /*\r
10475                  * Squirrel away the password. (We may need it later if\r
10476                  * asked to change it.)\r
10477                  */\r
10478                 s->password = dupstr(s->cur_prompt->prompts[0]->result);\r
10479                 free_prompts(s->cur_prompt);\r
10481                 /*\r
10482                  * Send the password packet.\r
10483                  *\r
10484                  * We pad out the password packet to 256 bytes to make\r
10485                  * it harder for an attacker to find the length of the\r
10486                  * user's password.\r
10487                  *\r
10488                  * Anyone using a password longer than 256 bytes\r
10489                  * probably doesn't have much to worry about from\r
10490                  * people who find out how long their password is!\r
10491                  */\r
10492                 s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
10493                 ssh2_pkt_addstring(s->pktout, ssh->username);\r
10494                 ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
10495                                                         /* service requested */\r
10496                 ssh2_pkt_addstring(s->pktout, "password");\r
10497                 ssh2_pkt_addbool(s->pktout, FALSE);\r
10498                 ssh2_pkt_addstring(s->pktout, s->password);\r
10499                 ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
10500                 logevent("Sent password");\r
10501                 s->type = AUTH_TYPE_PASSWORD;\r
10503                 /*\r
10504                  * Wait for next packet, in case it's a password change\r
10505                  * request.\r
10506                  */\r
10507                 crWaitUntilV(pktin);\r
10508                 changereq_first_time = TRUE;\r
10510                 while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {\r
10512                     /* \r
10513                      * We're being asked for a new password\r
10514                      * (perhaps not for the first time).\r
10515                      * Loop until the server accepts it.\r
10516                      */\r
10518                     int got_new = FALSE; /* not live over crReturn */\r
10519                     char *prompt;   /* not live over crReturn */\r
10520                     int prompt_len; /* not live over crReturn */\r
10521                     \r
10522                     {\r
10523                         const char *msg;\r
10524                         if (changereq_first_time)\r
10525                             msg = "Server requested password change";\r
10526                         else\r
10527                             msg = "Server rejected new password";\r
10528                         logevent(msg);\r
10529                         c_write_str(ssh, msg);\r
10530                         c_write_str(ssh, "\r\n");\r
10531                     }\r
10533                     ssh_pkt_getstring(pktin, &prompt, &prompt_len);\r
10535                     s->cur_prompt = new_prompts(ssh->frontend);\r
10536                     s->cur_prompt->to_server = TRUE;\r
10537                     s->cur_prompt->name = dupstr("New SSH password");\r
10538                     s->cur_prompt->instruction =\r
10539                         dupprintf("%.*s", prompt_len, NULLTOEMPTY(prompt));\r
10540                     s->cur_prompt->instr_reqd = TRUE;\r
10541                     /*\r
10542                      * There's no explicit requirement in the protocol\r
10543                      * for the "old" passwords in the original and\r
10544                      * password-change messages to be the same, and\r
10545                      * apparently some Cisco kit supports password change\r
10546                      * by the user entering a blank password originally\r
10547                      * and the real password subsequently, so,\r
10548                      * reluctantly, we prompt for the old password again.\r
10549                      *\r
10550                      * (On the other hand, some servers don't even bother\r
10551                      * to check this field.)\r
10552                      */\r
10553                     add_prompt(s->cur_prompt,\r
10554                                dupstr("Current password (blank for previously entered password): "),\r
10555                                FALSE);\r
10556                     add_prompt(s->cur_prompt, dupstr("Enter new password: "),\r
10557                                FALSE);\r
10558                     add_prompt(s->cur_prompt, dupstr("Confirm new password: "),\r
10559                                FALSE);\r
10561                     /*\r
10562                      * Loop until the user manages to enter the same\r
10563                      * password twice.\r
10564                      */\r
10565                     while (!got_new) {\r
10567                         ret = get_userpass_input(s->cur_prompt, NULL, 0);\r
10568                         while (ret < 0) {\r
10569                             ssh->send_ok = 1;\r
10570                             crWaitUntilV(!pktin);\r
10571                             ret = get_userpass_input(s->cur_prompt, in, inlen);\r
10572                             ssh->send_ok = 0;\r
10573                         }\r
10574                         if (!ret) {\r
10575                             /*\r
10576                              * Failed to get responses. Terminate.\r
10577                              */\r
10578                             /* burn the evidence */\r
10579                             free_prompts(s->cur_prompt);\r
10580                             smemclr(s->password, strlen(s->password));\r
10581                             sfree(s->password);\r
10582                             ssh_disconnect(ssh, NULL, "Unable to authenticate",\r
10583                                            SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,\r
10584                                            TRUE);\r
10585                             crStopV;\r
10586                         }\r
10588                         /*\r
10589                          * If the user specified a new original password\r
10590                          * (IYSWIM), overwrite any previously specified\r
10591                          * one.\r
10592                          * (A side effect is that the user doesn't have to\r
10593                          * re-enter it if they louse up the new password.)\r
10594                          */\r
10595                         if (s->cur_prompt->prompts[0]->result[0]) {\r
10596                             smemclr(s->password, strlen(s->password));\r
10597                                 /* burn the evidence */\r
10598                             sfree(s->password);\r
10599                             s->password =\r
10600                                 dupstr(s->cur_prompt->prompts[0]->result);\r
10601                         }\r
10603                         /*\r
10604                          * Check the two new passwords match.\r
10605                          */\r
10606                         got_new = (strcmp(s->cur_prompt->prompts[1]->result,\r
10607                                           s->cur_prompt->prompts[2]->result)\r
10608                                    == 0);\r
10609                         if (!got_new)\r
10610                             /* They don't. Silly user. */\r
10611                             c_write_str(ssh, "Passwords do not match\r\n");\r
10613                     }\r
10615                     /*\r
10616                      * Send the new password (along with the old one).\r
10617                      * (see above for padding rationale)\r
10618                      */\r
10619                     s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);\r
10620                     ssh2_pkt_addstring(s->pktout, ssh->username);\r
10621                     ssh2_pkt_addstring(s->pktout, "ssh-connection");\r
10622                                                         /* service requested */\r
10623                     ssh2_pkt_addstring(s->pktout, "password");\r
10624                     ssh2_pkt_addbool(s->pktout, TRUE);\r
10625                     ssh2_pkt_addstring(s->pktout, s->password);\r
10626                     ssh2_pkt_addstring(s->pktout,\r
10627                                        s->cur_prompt->prompts[1]->result);\r
10628                     free_prompts(s->cur_prompt);\r
10629                     ssh2_pkt_send_with_padding(ssh, s->pktout, 256);\r
10630                     logevent("Sent new password");\r
10631                     \r
10632                     /*\r
10633                      * Now see what the server has to say about it.\r
10634                      * (If it's CHANGEREQ again, it's not happy with the\r
10635                      * new password.)\r
10636                      */\r
10637                     crWaitUntilV(pktin);\r
10638                     changereq_first_time = FALSE;\r
10640                 }\r
10642                 /*\r
10643                  * We need to reexamine the current pktin at the top\r
10644                  * of the loop. Either:\r
10645                  *  - we weren't asked to change password at all, in\r
10646                  *    which case it's a SUCCESS or FAILURE with the\r
10647                  *    usual meaning\r
10648                  *  - we sent a new password, and the server was\r
10649                  *    either OK with it (SUCCESS or FAILURE w/partial\r
10650                  *    success) or unhappy with the _old_ password\r
10651                  *    (FAILURE w/o partial success)\r
10652                  * In any of these cases, we go back to the top of\r
10653                  * the loop and start again.\r
10654                  */\r
10655                 s->gotit = TRUE;\r
10657                 /*\r
10658                  * We don't need the old password any more, in any\r
10659                  * case. Burn the evidence.\r
10660                  */\r
10661                 smemclr(s->password, strlen(s->password));\r
10662                 sfree(s->password);\r
10664             } else {\r
10665                 char *str = dupprintf("No supported authentication methods available"\r
10666                                       " (server sent: %.*s)",\r
10667                                       methlen, methods);\r
10669                 ssh_disconnect(ssh, str,\r
10670                                "No supported authentication methods available",\r
10671                                SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,\r
10672                                FALSE);\r
10673                 sfree(str);\r
10675                 crStopV;\r
10677             }\r
10679         }\r
10680     }\r
10681     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;\r
10683     /* Clear up various bits and pieces from authentication. */\r
10684     if (s->publickey_blob) {\r
10685         sfree(s->publickey_algorithm);\r
10686         sfree(s->publickey_blob);\r
10687         sfree(s->publickey_comment);\r
10688     }\r
10689     if (s->agent_response)\r
10690         sfree(s->agent_response);\r
10692     if (s->userauth_success && !ssh->bare_connection) {\r
10693         /*\r
10694          * We've just received USERAUTH_SUCCESS, and we haven't sent any\r
10695          * packets since. Signal the transport layer to consider enacting\r
10696          * delayed compression.\r
10697          *\r
10698          * (Relying on we_are_in is not sufficient, as\r
10699          * draft-miller-secsh-compression-delayed is quite clear that it\r
10700          * triggers on USERAUTH_SUCCESS specifically, and we_are_in can\r
10701          * become set for other reasons.)\r
10702          */\r
10703         do_ssh2_transport(ssh, "enabling delayed compression", -2, NULL);\r
10704     }\r
10706     ssh->channels = newtree234(ssh_channelcmp);\r
10708     /*\r
10709      * Set up handlers for some connection protocol messages, so we\r
10710      * don't have to handle them repeatedly in this coroutine.\r
10711      */\r
10712     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] =\r
10713         ssh2_msg_channel_window_adjust;\r
10714     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] =\r
10715         ssh2_msg_global_request;\r
10717     /*\r
10718      * Create the main session channel.\r
10719      */\r
10720     if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) {\r
10721         ssh->mainchan = NULL;\r
10722     } else {\r
10723         ssh->mainchan = snew(struct ssh_channel);\r
10724         ssh->mainchan->ssh = ssh;\r
10725         ssh_channel_init(ssh->mainchan);\r
10727         if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) {\r
10728             /*\r
10729              * Just start a direct-tcpip channel and use it as the main\r
10730              * channel.\r
10731              */\r
10732             ssh_send_port_open(ssh->mainchan,\r
10733                                conf_get_str(ssh->conf, CONF_ssh_nc_host),\r
10734                                conf_get_int(ssh->conf, CONF_ssh_nc_port),\r
10735                                "main channel");\r
10736             ssh->ncmode = TRUE;\r
10737         } else {\r
10738             s->pktout = ssh2_chanopen_init(ssh->mainchan, "session");\r
10739             logevent("Opening session as main channel");\r
10740             ssh2_pkt_send(ssh, s->pktout);\r
10741             ssh->ncmode = FALSE;\r
10742         }\r
10743         crWaitUntilV(pktin);\r
10744         if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION &&\r
10745             pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) {\r
10746             bombout(("Server sent strange packet %d in response to main "\r
10747                      "channel open request", pktin->type));\r
10748             crStopV;\r
10749         }\r
10750         if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {\r
10751             bombout(("Server's response to main channel open cited wrong"\r
10752                      " channel number"));\r
10753             crStopV;\r
10754         }\r
10755         if (pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {\r
10756             char *errtext = ssh2_channel_open_failure_error_text(pktin);\r
10757             bombout(("Server refused to open main channel: %s", errtext));\r
10758             sfree(errtext);\r
10759             crStopV;\r
10760         }\r
10762         ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);\r
10763         ssh->mainchan->halfopen = FALSE;\r
10764         ssh->mainchan->type = CHAN_MAINSESSION;\r
10765         ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);\r
10766         ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);\r
10767         update_specials_menu(ssh->frontend);\r
10768         logevent("Opened main channel");\r
10769     }\r
10771     /*\r
10772      * Now we have a channel, make dispatch table entries for\r
10773      * general channel-based messages.\r
10774      */\r
10775     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] =\r
10776     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] =\r
10777         ssh2_msg_channel_data;\r
10778     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof;\r
10779     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close;\r
10780     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] =\r
10781         ssh2_msg_channel_open_confirmation;\r
10782     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] =\r
10783         ssh2_msg_channel_open_failure;\r
10784     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] =\r
10785         ssh2_msg_channel_request;\r
10786     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] =\r
10787         ssh2_msg_channel_open;\r
10788     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;\r
10789     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;\r
10791     /*\r
10792      * Now the connection protocol is properly up and running, with\r
10793      * all those dispatch table entries, so it's safe to let\r
10794      * downstreams start trying to open extra channels through us.\r
10795      */\r
10796     if (ssh->connshare)\r
10797         share_activate(ssh->connshare, ssh->v_s);\r
10799     if (ssh->mainchan && ssh_is_simple(ssh)) {\r
10800         /*\r
10801          * This message indicates to the server that we promise\r
10802          * not to try to run any other channel in parallel with\r
10803          * this one, so it's safe for it to advertise a very large\r
10804          * window and leave the flow control to TCP.\r
10805          */\r
10806         s->pktout = ssh2_chanreq_init(ssh->mainchan,\r
10807                                       "simple@putty.projects.tartarus.org",\r
10808                                       NULL, NULL);\r
10809         ssh2_pkt_send(ssh, s->pktout);\r
10810     }\r
10812     /*\r
10813      * Enable port forwardings.\r
10814      */\r
10815     ssh_setup_portfwd(ssh, ssh->conf);\r
10817     if (ssh->mainchan && !ssh->ncmode) {\r
10818         /*\r
10819          * Send the CHANNEL_REQUESTS for the main session channel.\r
10820          * Each one is handled by its own little asynchronous\r
10821          * co-routine.\r
10822          */\r
10824         /* Potentially enable X11 forwarding. */\r
10825         if (conf_get_int(ssh->conf, CONF_x11_forward)) {\r
10826             ssh->x11disp =\r
10827                 x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),\r
10828                                   ssh->conf);\r
10829             if (!ssh->x11disp) {\r
10830                 /* FIXME: return an error message from x11_setup_display */\r
10831                 logevent("X11 forwarding not enabled: unable to"\r
10832                          " initialise X display");\r
10833             } else {\r
10834                 ssh->x11auth = x11_invent_fake_auth\r
10835                     (ssh->x11authtree, conf_get_int(ssh->conf, CONF_x11_auth));\r
10836                 ssh->x11auth->disp = ssh->x11disp;\r
10838                 ssh2_setup_x11(ssh->mainchan, NULL, NULL);\r
10839             }\r
10840         }\r
10842         /* Potentially enable agent forwarding. */\r
10843         if (ssh_agent_forwarding_permitted(ssh))\r
10844             ssh2_setup_agent(ssh->mainchan, NULL, NULL);\r
10846         /* Now allocate a pty for the session. */\r
10847         if (!conf_get_int(ssh->conf, CONF_nopty))\r
10848             ssh2_setup_pty(ssh->mainchan, NULL, NULL);\r
10850         /* Send environment variables. */\r
10851         ssh2_setup_env(ssh->mainchan, NULL, NULL);\r
10853         /*\r
10854          * Start a shell or a remote command. We may have to attempt\r
10855          * this twice if the config data has provided a second choice\r
10856          * of command.\r
10857          */\r
10858         while (1) {\r
10859             int subsys;\r
10860             char *cmd;\r
10862             if (ssh->fallback_cmd) {\r
10863                 subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2);\r
10864                 cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);\r
10865             } else {\r
10866                 subsys = conf_get_int(ssh->conf, CONF_ssh_subsys);\r
10867                 cmd = conf_get_str(ssh->conf, CONF_remote_cmd);\r
10868             }\r
10870             if (subsys) {\r
10871                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem",\r
10872                                               ssh2_response_authconn, NULL);\r
10873                 ssh2_pkt_addstring(s->pktout, cmd);\r
10874             } else if (*cmd) {\r
10875                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec",\r
10876                                               ssh2_response_authconn, NULL);\r
10877                 ssh2_pkt_addstring(s->pktout, cmd);\r
10878             } else {\r
10879                 s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell",\r
10880                                               ssh2_response_authconn, NULL);\r
10881             }\r
10882             ssh2_pkt_send(ssh, s->pktout);\r
10884             crWaitUntilV(pktin);\r
10886             if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {\r
10887                 if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {\r
10888                     bombout(("Unexpected response to shell/command request:"\r
10889                              " packet type %d", pktin->type));\r
10890                     crStopV;\r
10891                 }\r
10892                 /*\r
10893                  * We failed to start the command. If this is the\r
10894                  * fallback command, we really are finished; if it's\r
10895                  * not, and if the fallback command exists, try falling\r
10896                  * back to it before complaining.\r
10897                  */\r
10898                 if (!ssh->fallback_cmd &&\r
10899                     *conf_get_str(ssh->conf, CONF_remote_cmd2)) {\r
10900                     logevent("Primary command failed; attempting fallback");\r
10901                     ssh->fallback_cmd = TRUE;\r
10902                     continue;\r
10903                 }\r
10904                 bombout(("Server refused to start a shell/command"));\r
10905                 crStopV;\r
10906             } else {\r
10907                 logevent("Started a shell/command");\r
10908             }\r
10909             break;\r
10910         }\r
10911     } else {\r
10912         ssh->editing = ssh->echoing = TRUE;\r
10913     }\r
10915     ssh->state = SSH_STATE_SESSION;\r
10916     if (ssh->size_needed)\r
10917         ssh_size(ssh, ssh->term_width, ssh->term_height);\r
10918     if (ssh->eof_needed)\r
10919         ssh_special(ssh, TS_EOF);\r
10921     /*\r
10922      * Transfer data!\r
10923      */\r
10924     if (ssh->ldisc)\r
10925         ldisc_echoedit_update(ssh->ldisc);  /* cause ldisc to notice changes */\r
10926     if (ssh->mainchan)\r
10927         ssh->send_ok = 1;\r
10928     while (1) {\r
10929         crReturnV;\r
10930         if (pktin) {\r
10932             /*\r
10933              * _All_ the connection-layer packets we expect to\r
10934              * receive are now handled by the dispatch table.\r
10935              * Anything that reaches here must be bogus.\r
10936              */\r
10938             bombout(("Strange packet received: type %d", pktin->type));\r
10939             crStopV;\r
10940         } else if (ssh->mainchan) {\r
10941             /*\r
10942              * We have spare data. Add it to the channel buffer.\r
10943              */\r
10944             ssh_send_channel_data(ssh->mainchan, (char *)in, inlen);\r
10945         }\r
10946     }\r
10948     crFinishV;\r
10951 /*\r
10952  * Handlers for SSH-2 messages that might arrive at any moment.\r
10953  */\r
10954 static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)\r
10956     /* log reason code in disconnect message */\r
10957     char *buf, *msg;\r
10958     int reason, msglen;\r
10960     reason = ssh_pkt_getuint32(pktin);\r
10961     ssh_pkt_getstring(pktin, &msg, &msglen);\r
10963     if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {\r
10964         buf = dupprintf("Received disconnect message (%s)",\r
10965                         ssh2_disconnect_reasons[reason]);\r
10966     } else {\r
10967         buf = dupprintf("Received disconnect message (unknown"\r
10968                         " type %d)", reason);\r
10969     }\r
10970     logevent(buf);\r
10971     sfree(buf);\r
10972     buf = dupprintf("Disconnection message text: %.*s",\r
10973                     msglen, NULLTOEMPTY(msg));\r
10974     logevent(buf);\r
10975     bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"",\r
10976              reason,\r
10977              (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?\r
10978              ssh2_disconnect_reasons[reason] : "unknown",\r
10979              msglen, NULLTOEMPTY(msg)));\r
10980     sfree(buf);\r
10983 static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)\r
10985     /* log the debug message */\r
10986     char *msg;\r
10987     int msglen;\r
10989     /* XXX maybe we should actually take notice of the return value */\r
10990     ssh2_pkt_getbool(pktin);\r
10991     ssh_pkt_getstring(pktin, &msg, &msglen);\r
10993     logeventf(ssh, "Remote debug message: %.*s", msglen, NULLTOEMPTY(msg));\r
10996 static void ssh2_msg_transport(Ssh ssh, struct Packet *pktin)\r
10998     do_ssh2_transport(ssh, NULL, 0, pktin);\r
11001 /*\r
11002  * Called if we receive a packet that isn't allowed by the protocol.\r
11003  * This only applies to packets whose meaning PuTTY understands.\r
11004  * Entirely unknown packets are handled below.\r
11005  */\r
11006 static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin)\r
11008     char *buf = dupprintf("Server protocol violation: unexpected %s packet",\r
11009                           ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,\r
11010                                         pktin->type));\r
11011     ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);\r
11012     sfree(buf);\r
11015 static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)\r
11017     struct Packet *pktout;\r
11018     pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);\r
11019     ssh2_pkt_adduint32(pktout, pktin->sequence);\r
11020     /*\r
11021      * UNIMPLEMENTED messages MUST appear in the same order as the\r
11022      * messages they respond to. Hence, never queue them.\r
11023      */\r
11024     ssh2_pkt_send_noqueue(ssh, pktout);\r
11027 /*\r
11028  * Handle the top-level SSH-2 protocol.\r
11029  */\r
11030 static void ssh2_protocol_setup(Ssh ssh)\r
11032     int i;\r
11034     /*\r
11035      * Most messages cause SSH2_MSG_UNIMPLEMENTED.\r
11036      */\r
11037     for (i = 0; i < 256; i++)\r
11038         ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;\r
11040     /*\r
11041      * Initially, we only accept transport messages (and a few generic\r
11042      * ones).  do_ssh2_authconn will add more when it starts.\r
11043      * Messages that are understood but not currently acceptable go to\r
11044      * ssh2_msg_unexpected.\r
11045      */\r
11046     ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected;\r
11047     ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = ssh2_msg_unexpected;\r
11048     ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_unexpected;\r
11049     ssh->packet_dispatch[SSH2_MSG_KEXINIT] = ssh2_msg_transport;\r
11050     ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = ssh2_msg_transport;\r
11051     ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = ssh2_msg_transport;\r
11052     ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = ssh2_msg_transport;\r
11053     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = ssh2_msg_transport; duplicate case value */\r
11054     /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = ssh2_msg_transport; duplicate case value */\r
11055     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = ssh2_msg_transport;\r
11056     ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = ssh2_msg_transport;\r
11057     ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_unexpected;\r
11058     ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_unexpected;\r
11059     ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_unexpected;\r
11060     ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_unexpected;\r
11061     ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_unexpected;\r
11062     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_unexpected; duplicate case value */\r
11063     /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_unexpected; duplicate case value */\r
11064     ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_unexpected;\r
11065     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected;\r
11066     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected;\r
11067     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected;\r
11068     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected;\r
11069     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected;\r
11070     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected;\r
11071     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected;\r
11072     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected;\r
11073     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected;\r
11074     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected;\r
11075     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected;\r
11076     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected;\r
11077     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected;\r
11078     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected;\r
11080     /*\r
11081      * These messages have a special handler from the start.\r
11082      */\r
11083     ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;\r
11084     ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with SSH-1 */\r
11085     ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;\r
11088 static void ssh2_bare_connection_protocol_setup(Ssh ssh)\r
11090     int i;\r
11092     /*\r
11093      * Most messages cause SSH2_MSG_UNIMPLEMENTED.\r
11094      */\r
11095     for (i = 0; i < 256; i++)\r
11096         ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;\r
11098     /*\r
11099      * Initially, we set all ssh-connection messages to 'unexpected';\r
11100      * do_ssh2_authconn will fill things in properly. We also handle a\r
11101      * couple of messages from the transport protocol which aren't\r
11102      * related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG,\r
11103      * DISCONNECT).\r
11104      */\r
11105     ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected;\r
11106     ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected;\r
11107     ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected;\r
11108     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected;\r
11109     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected;\r
11110     ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected;\r
11111     ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected;\r
11112     ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected;\r
11113     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected;\r
11114     ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected;\r
11115     ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected;\r
11116     ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected;\r
11117     ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected;\r
11118     ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected;\r
11120     ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected;\r
11122     /*\r
11123      * These messages have a special handler from the start.\r
11124      */\r
11125     ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;\r
11126     ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore;\r
11127     ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;\r
11130 static void ssh2_timer(void *ctx, unsigned long now)\r
11132     Ssh ssh = (Ssh)ctx;\r
11134     if (ssh->state == SSH_STATE_CLOSED)\r
11135         return;\r
11137     if (!ssh->kex_in_progress && !ssh->bare_connection &&\r
11138         conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0 &&\r
11139         now == ssh->next_rekey) {\r
11140         do_ssh2_transport(ssh, "timeout", -1, NULL);\r
11141     }\r
11144 static void ssh2_protocol(Ssh ssh, const void *vin, int inlen,\r
11145                           struct Packet *pktin)\r
11147     const unsigned char *in = (const unsigned char *)vin;\r
11148     if (ssh->state == SSH_STATE_CLOSED)\r
11149         return;\r
11151     if (pktin) {\r
11152         ssh->incoming_data_size += pktin->encrypted_len;\r
11153         if (!ssh->kex_in_progress &&\r
11154             ssh->max_data_size != 0 &&\r
11155             ssh->incoming_data_size > ssh->max_data_size)\r
11156             do_ssh2_transport(ssh, "too much data received", -1, NULL);\r
11157     }\r
11159     if (pktin)\r
11160         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
11161     else if (!ssh->protocol_initial_phase_done)\r
11162         do_ssh2_transport(ssh, in, inlen, pktin);\r
11163     else\r
11164         do_ssh2_authconn(ssh, in, inlen, pktin);\r
11167 static void ssh2_bare_connection_protocol(Ssh ssh, const void *vin, int inlen,\r
11168                                           struct Packet *pktin)\r
11170     const unsigned char *in = (const unsigned char *)vin;\r
11171     if (ssh->state == SSH_STATE_CLOSED)\r
11172         return;\r
11174     if (pktin)\r
11175         ssh->packet_dispatch[pktin->type](ssh, pktin);\r
11176     else\r
11177         do_ssh2_authconn(ssh, in, inlen, pktin);\r
11180 static void ssh_cache_conf_values(Ssh ssh)\r
11182     ssh->logomitdata = conf_get_int(ssh->conf, CONF_logomitdata);\r
11185 /*\r
11186  * Called to set up the connection.\r
11187  *\r
11188  * Returns an error message, or NULL on success.\r
11189  */\r
11190 static const char *ssh_init(void *frontend_handle, void **backend_handle,\r
11191                             Conf *conf,\r
11192                             const char *host, int port, char **realhost,\r
11193                             int nodelay, int keepalive)\r
11195     const char *p;\r
11196     Ssh ssh;\r
11198     ssh = snew(struct ssh_tag);\r
11199     ssh->conf = conf_copy(conf);\r
11200     ssh_cache_conf_values(ssh);\r
11201     ssh->version = 0;                  /* when not ready yet */\r
11202     ssh->s = NULL;\r
11203     ssh->cipher = NULL;\r
11204     ssh->v1_cipher_ctx = NULL;\r
11205     ssh->crcda_ctx = NULL;\r
11206     ssh->cscipher = NULL;\r
11207     ssh->cs_cipher_ctx = NULL;\r
11208     ssh->sccipher = NULL;\r
11209     ssh->sc_cipher_ctx = NULL;\r
11210     ssh->csmac = NULL;\r
11211     ssh->cs_mac_ctx = NULL;\r
11212     ssh->scmac = NULL;\r
11213     ssh->sc_mac_ctx = NULL;\r
11214     ssh->cscomp = NULL;\r
11215     ssh->cs_comp_ctx = NULL;\r
11216     ssh->sccomp = NULL;\r
11217     ssh->sc_comp_ctx = NULL;\r
11218     ssh->kex = NULL;\r
11219     ssh->kex_ctx = NULL;\r
11220     ssh->hostkey = NULL;\r
11221     ssh->hostkey_str = NULL;\r
11222     ssh->exitcode = -1;\r
11223     ssh->close_expected = FALSE;\r
11224     ssh->clean_exit = FALSE;\r
11225     ssh->state = SSH_STATE_PREPACKET;\r
11226     ssh->size_needed = FALSE;\r
11227     ssh->eof_needed = FALSE;\r
11228     ssh->ldisc = NULL;\r
11229     ssh->logctx = NULL;\r
11230     ssh->deferred_send_data = NULL;\r
11231     ssh->deferred_len = 0;\r
11232     ssh->deferred_size = 0;\r
11233     ssh->fallback_cmd = 0;\r
11234     ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;\r
11235     ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;\r
11236     ssh->x11disp = NULL;\r
11237     ssh->x11auth = NULL;\r
11238     ssh->x11authtree = newtree234(x11_authcmp);\r
11239     ssh->v1_compressing = FALSE;\r
11240     ssh->v2_outgoing_sequence = 0;\r
11241     ssh->ssh1_rdpkt_crstate = 0;\r
11242     ssh->ssh2_rdpkt_crstate = 0;\r
11243     ssh->ssh2_bare_rdpkt_crstate = 0;\r
11244     ssh->ssh_gotdata_crstate = 0;\r
11245     ssh->do_ssh1_connection_crstate = 0;\r
11246     ssh->do_ssh_init_state = NULL;\r
11247     ssh->do_ssh_connection_init_state = NULL;\r
11248     ssh->do_ssh1_login_state = NULL;\r
11249     ssh->do_ssh2_transport_state = NULL;\r
11250     ssh->do_ssh2_authconn_state = NULL;\r
11251     ssh->v_c = NULL;\r
11252     ssh->v_s = NULL;\r
11253     ssh->mainchan = NULL;\r
11254     ssh->throttled_all = 0;\r
11255     ssh->v1_stdout_throttling = 0;\r
11256     ssh->queue = NULL;\r
11257     ssh->queuelen = ssh->queuesize = 0;\r
11258     ssh->queueing = FALSE;\r
11259     ssh->qhead = ssh->qtail = NULL;\r
11260     ssh->deferred_rekey_reason = NULL;\r
11261     bufchain_init(&ssh->queued_incoming_data);\r
11262     ssh->frozen = FALSE;\r
11263     ssh->username = NULL;\r
11264     ssh->sent_console_eof = FALSE;\r
11265     ssh->got_pty = FALSE;\r
11266     ssh->bare_connection = FALSE;\r
11267     ssh->X11_fwd_enabled = FALSE;\r
11268     ssh->connshare = NULL;\r
11269     ssh->attempting_connshare = FALSE;\r
11270     ssh->session_started = FALSE;\r
11271     ssh->specials = NULL;\r
11272     ssh->n_uncert_hostkeys = 0;\r
11273     ssh->cross_certifying = FALSE;\r
11275     *backend_handle = ssh;\r
11277 #ifdef MSCRYPTOAPI\r
11278     if (crypto_startup() == 0)\r
11279         return "Microsoft high encryption pack not installed!";\r
11280 #endif\r
11282     ssh->frontend = frontend_handle;\r
11283     ssh->term_width = conf_get_int(ssh->conf, CONF_width);\r
11284     ssh->term_height = conf_get_int(ssh->conf, CONF_height);\r
11286     ssh->channels = NULL;\r
11287     ssh->rportfwds = NULL;\r
11288     ssh->portfwds = NULL;\r
11290     ssh->send_ok = 0;\r
11291     ssh->editing = 0;\r
11292     ssh->echoing = 0;\r
11293     ssh->conn_throttle_count = 0;\r
11294     ssh->overall_bufsize = 0;\r
11295     ssh->fallback_cmd = 0;\r
11297     ssh->protocol = NULL;\r
11299     ssh->protocol_initial_phase_done = FALSE;\r
11301     ssh->pinger = NULL;\r
11303     ssh->incoming_data_size = ssh->outgoing_data_size =\r
11304         ssh->deferred_data_size = 0L;\r
11305     ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf,\r
11306                                                       CONF_ssh_rekey_data));\r
11307     ssh->kex_in_progress = FALSE;\r
11309     ssh->auth_agent_query = NULL;\r
11311 #ifndef NO_GSSAPI\r
11312     ssh->gsslibs = NULL;\r
11313 #endif\r
11315     random_ref(); /* do this now - may be needed by sharing setup code */\r
11317     p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);\r
11318     if (p != NULL) {\r
11319         random_unref();\r
11320         return p;\r
11321     }\r
11323     return NULL;\r
11326 static void ssh_free(void *handle)\r
11328     Ssh ssh = (Ssh) handle;\r
11329     struct ssh_channel *c;\r
11330     struct ssh_rportfwd *pf;\r
11331     struct X11FakeAuth *auth;\r
11333     if (ssh->v1_cipher_ctx)\r
11334         ssh->cipher->free_context(ssh->v1_cipher_ctx);\r
11335     if (ssh->cs_cipher_ctx)\r
11336         ssh->cscipher->free_context(ssh->cs_cipher_ctx);\r
11337     if (ssh->sc_cipher_ctx)\r
11338         ssh->sccipher->free_context(ssh->sc_cipher_ctx);\r
11339     if (ssh->cs_mac_ctx)\r
11340         ssh->csmac->free_context(ssh->cs_mac_ctx);\r
11341     if (ssh->sc_mac_ctx)\r
11342         ssh->scmac->free_context(ssh->sc_mac_ctx);\r
11343     if (ssh->cs_comp_ctx) {\r
11344         if (ssh->cscomp)\r
11345             ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);\r
11346         else\r
11347             zlib_compress_cleanup(ssh->cs_comp_ctx);\r
11348     }\r
11349     if (ssh->sc_comp_ctx) {\r
11350         if (ssh->sccomp)\r
11351             ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);\r
11352         else\r
11353             zlib_decompress_cleanup(ssh->sc_comp_ctx);\r
11354     }\r
11355     if (ssh->kex_ctx)\r
11356         dh_cleanup(ssh->kex_ctx);\r
11357     sfree(ssh->savedhost);\r
11359     while (ssh->queuelen-- > 0)\r
11360         ssh_free_packet(ssh->queue[ssh->queuelen]);\r
11361     sfree(ssh->queue);\r
11363     while (ssh->qhead) {\r
11364         struct queued_handler *qh = ssh->qhead;\r
11365         ssh->qhead = qh->next;\r
11366         sfree(qh);\r
11367     }\r
11368     ssh->qhead = ssh->qtail = NULL;\r
11370     if (ssh->channels) {\r
11371         while ((c = delpos234(ssh->channels, 0)) != NULL) {\r
11372             ssh_channel_close_local(c, NULL);\r
11373             if (ssh->version == 2) {\r
11374                 struct outstanding_channel_request *ocr, *nocr;\r
11375                 ocr = c->v.v2.chanreq_head;\r
11376                 while (ocr) {\r
11377                     ocr->handler(c, NULL, ocr->ctx);\r
11378                     nocr = ocr->next;\r
11379                     sfree(ocr);\r
11380                     ocr = nocr;\r
11381                 }\r
11382                 bufchain_clear(&c->v.v2.outbuffer);\r
11383             }\r
11384             sfree(c);\r
11385         }\r
11386         freetree234(ssh->channels);\r
11387         ssh->channels = NULL;\r
11388     }\r
11390     if (ssh->connshare)\r
11391         sharestate_free(ssh->connshare);\r
11393     if (ssh->rportfwds) {\r
11394         while ((pf = delpos234(ssh->rportfwds, 0)) != NULL)\r
11395             free_rportfwd(pf);\r
11396         freetree234(ssh->rportfwds);\r
11397         ssh->rportfwds = NULL;\r
11398     }\r
11399     sfree(ssh->deferred_send_data);\r
11400     if (ssh->x11disp)\r
11401         x11_free_display(ssh->x11disp);\r
11402     while ((auth = delpos234(ssh->x11authtree, 0)) != NULL)\r
11403         x11_free_fake_auth(auth);\r
11404     freetree234(ssh->x11authtree);\r
11405     sfree(ssh->do_ssh_init_state);\r
11406     sfree(ssh->do_ssh1_login_state);\r
11407     sfree(ssh->do_ssh2_transport_state);\r
11408     sfree(ssh->do_ssh2_authconn_state);\r
11409     sfree(ssh->v_c);\r
11410     sfree(ssh->v_s);\r
11411     sfree(ssh->fullhostname);\r
11412     sfree(ssh->hostkey_str);\r
11413     sfree(ssh->specials);\r
11414     if (ssh->crcda_ctx) {\r
11415         crcda_free_context(ssh->crcda_ctx);\r
11416         ssh->crcda_ctx = NULL;\r
11417     }\r
11418     if (ssh->s)\r
11419         ssh_do_close(ssh, TRUE);\r
11420     expire_timer_context(ssh);\r
11421     if (ssh->pinger)\r
11422         pinger_free(ssh->pinger);\r
11423     bufchain_clear(&ssh->queued_incoming_data);\r
11424     sfree(ssh->username);\r
11425     conf_free(ssh->conf);\r
11427     if (ssh->auth_agent_query)\r
11428         agent_cancel_query(ssh->auth_agent_query);\r
11430 #ifndef NO_GSSAPI\r
11431     if (ssh->gsslibs)\r
11432         ssh_gss_cleanup(ssh->gsslibs);\r
11433 #endif\r
11434     sfree(ssh);\r
11436     random_unref();\r
11439 /*\r
11440  * Reconfigure the SSH backend.\r
11441  */\r
11442 static void ssh_reconfig(void *handle, Conf *conf)\r
11444     Ssh ssh = (Ssh) handle;\r
11445     const char *rekeying = NULL;\r
11446     int rekey_mandatory = FALSE;\r
11447     unsigned long old_max_data_size;\r
11448     int i, rekey_time;\r
11450     pinger_reconfig(ssh->pinger, ssh->conf, conf);\r
11451     if (ssh->portfwds)\r
11452         ssh_setup_portfwd(ssh, conf);\r
11454     rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);\r
11455     if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != rekey_time &&\r
11456         rekey_time != 0) {\r
11457         unsigned long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;\r
11458         unsigned long now = GETTICKCOUNT();\r
11460         if (now - ssh->last_rekey > rekey_time*60*TICKSPERSEC) {\r
11461             rekeying = "timeout shortened";\r
11462         } else {\r
11463             ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh);\r
11464         }\r
11465     }\r
11467     old_max_data_size = ssh->max_data_size;\r
11468     ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf,\r
11469                                                       CONF_ssh_rekey_data));\r
11470     if (old_max_data_size != ssh->max_data_size &&\r
11471         ssh->max_data_size != 0) {\r
11472         if (ssh->outgoing_data_size > ssh->max_data_size ||\r
11473             ssh->incoming_data_size > ssh->max_data_size)\r
11474             rekeying = "data limit lowered";\r
11475     }\r
11477     if (conf_get_int(ssh->conf, CONF_compression) !=\r
11478         conf_get_int(conf, CONF_compression)) {\r
11479         rekeying = "compression setting changed";\r
11480         rekey_mandatory = TRUE;\r
11481     }\r
11483     for (i = 0; i < CIPHER_MAX; i++)\r
11484         if (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i) !=\r
11485             conf_get_int_int(conf, CONF_ssh_cipherlist, i)) {\r
11486         rekeying = "cipher settings changed";\r
11487         rekey_mandatory = TRUE;\r
11488     }\r
11489     if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc) !=\r
11490         conf_get_int(conf, CONF_ssh2_des_cbc)) {\r
11491         rekeying = "cipher settings changed";\r
11492         rekey_mandatory = TRUE;\r
11493     }\r
11495     conf_free(ssh->conf);\r
11496     ssh->conf = conf_copy(conf);\r
11497     ssh_cache_conf_values(ssh);\r
11499     if (!ssh->bare_connection && rekeying) {\r
11500         if (!ssh->kex_in_progress) {\r
11501             do_ssh2_transport(ssh, rekeying, -1, NULL);\r
11502         } else if (rekey_mandatory) {\r
11503             ssh->deferred_rekey_reason = rekeying;\r
11504         }\r
11505     }\r
11508 /*\r
11509  * Called to send data down the SSH connection.\r
11510  */\r
11511 static int ssh_send(void *handle, const char *buf, int len)\r
11513     Ssh ssh = (Ssh) handle;\r
11515     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
11516         return 0;\r
11518     ssh->protocol(ssh, (const unsigned char *)buf, len, 0);\r
11520     return ssh_sendbuffer(ssh);\r
11523 /*\r
11524  * Called to query the current amount of buffered stdin data.\r
11525  */\r
11526 static int ssh_sendbuffer(void *handle)\r
11528     Ssh ssh = (Ssh) handle;\r
11529     int override_value;\r
11531     if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL)\r
11532         return 0;\r
11534     /*\r
11535      * If the SSH socket itself has backed up, add the total backup\r
11536      * size on that to any individual buffer on the stdin channel.\r
11537      */\r
11538     override_value = 0;\r
11539     if (ssh->throttled_all)\r
11540         override_value = ssh->overall_bufsize;\r
11542     if (ssh->version == 1) {\r
11543         return override_value;\r
11544     } else if (ssh->version == 2) {\r
11545         if (!ssh->mainchan)\r
11546             return override_value;\r
11547         else\r
11548             return (override_value +\r
11549                     bufchain_size(&ssh->mainchan->v.v2.outbuffer));\r
11550     }\r
11552     return 0;\r
11555 /*\r
11556  * Called to set the size of the window from SSH's POV.\r
11557  */\r
11558 static void ssh_size(void *handle, int width, int height)\r
11560     Ssh ssh = (Ssh) handle;\r
11561     struct Packet *pktout;\r
11563     ssh->term_width = width;\r
11564     ssh->term_height = height;\r
11566     switch (ssh->state) {\r
11567       case SSH_STATE_BEFORE_SIZE:\r
11568       case SSH_STATE_PREPACKET:\r
11569       case SSH_STATE_CLOSED:\r
11570         break;                         /* do nothing */\r
11571       case SSH_STATE_INTERMED:\r
11572         ssh->size_needed = TRUE;       /* buffer for later */\r
11573         break;\r
11574       case SSH_STATE_SESSION:\r
11575         if (!conf_get_int(ssh->conf, CONF_nopty)) {\r
11576             if (ssh->version == 1) {\r
11577                 send_packet(ssh, SSH1_CMSG_WINDOW_SIZE,\r
11578                             PKT_INT, ssh->term_height,\r
11579                             PKT_INT, ssh->term_width,\r
11580                             PKT_INT, 0, PKT_INT, 0, PKT_END);\r
11581             } else if (ssh->mainchan) {\r
11582                 pktout = ssh2_chanreq_init(ssh->mainchan, "window-change",\r
11583                                            NULL, NULL);\r
11584                 ssh2_pkt_adduint32(pktout, ssh->term_width);\r
11585                 ssh2_pkt_adduint32(pktout, ssh->term_height);\r
11586                 ssh2_pkt_adduint32(pktout, 0);\r
11587                 ssh2_pkt_adduint32(pktout, 0);\r
11588                 ssh2_pkt_send(ssh, pktout);\r
11589             }\r
11590         }\r
11591         break;\r
11592     }\r
11595 /*\r
11596  * Return a list of the special codes that make sense in this\r
11597  * protocol.\r
11598  */\r
11599 static const struct telnet_special *ssh_get_specials(void *handle)\r
11601     static const struct telnet_special ssh1_ignore_special[] = {\r
11602         {"IGNORE message", TS_NOP}\r
11603     };\r
11604     static const struct telnet_special ssh2_ignore_special[] = {\r
11605         {"IGNORE message", TS_NOP},\r
11606     };\r
11607     static const struct telnet_special ssh2_rekey_special[] = {\r
11608         {"Repeat key exchange", TS_REKEY},\r
11609     };\r
11610     static const struct telnet_special ssh2_session_specials[] = {\r
11611         {NULL, TS_SEP},\r
11612         {"Break", TS_BRK},\r
11613         /* These are the signal names defined by RFC 4254.\r
11614          * They include all the ISO C signals, but are a subset of the POSIX\r
11615          * required signals. */\r
11616         {"SIGINT (Interrupt)", TS_SIGINT},\r
11617         {"SIGTERM (Terminate)", TS_SIGTERM},\r
11618         {"SIGKILL (Kill)", TS_SIGKILL},\r
11619         {"SIGQUIT (Quit)", TS_SIGQUIT},\r
11620         {"SIGHUP (Hangup)", TS_SIGHUP},\r
11621         {"More signals", TS_SUBMENU},\r
11622           {"SIGABRT", TS_SIGABRT}, {"SIGALRM", TS_SIGALRM},\r
11623           {"SIGFPE",  TS_SIGFPE},  {"SIGILL",  TS_SIGILL},\r
11624           {"SIGPIPE", TS_SIGPIPE}, {"SIGSEGV", TS_SIGSEGV},\r
11625           {"SIGUSR1", TS_SIGUSR1}, {"SIGUSR2", TS_SIGUSR2},\r
11626         {NULL, TS_EXITMENU}\r
11627     };\r
11628     static const struct telnet_special specials_end[] = {\r
11629         {NULL, TS_EXITMENU}\r
11630     };\r
11632     struct telnet_special *specials = NULL;\r
11633     int nspecials = 0, specialsize = 0;\r
11635     Ssh ssh = (Ssh) handle;\r
11637     sfree(ssh->specials);\r
11639 #define ADD_SPECIALS(name) do                                           \\r
11640     {                                                                   \\r
11641         int len = lenof(name);                                          \\r
11642         if (nspecials + len > specialsize) {                            \\r
11643             specialsize = (nspecials + len) * 5 / 4 + 32;               \\r
11644             specials = sresize(specials, specialsize, struct telnet_special); \\r
11645         }                                                               \\r
11646         memcpy(specials+nspecials, name, len*sizeof(struct telnet_special)); \\r
11647         nspecials += len;                                               \\r
11648     } while (0)\r
11650     if (ssh->version == 1) {\r
11651         /* Don't bother offering IGNORE if we've decided the remote\r
11652          * won't cope with it, since we wouldn't bother sending it if\r
11653          * asked anyway. */\r
11654         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
11655             ADD_SPECIALS(ssh1_ignore_special);\r
11656     } else if (ssh->version == 2) {\r
11657         if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE))\r
11658             ADD_SPECIALS(ssh2_ignore_special);\r
11659         if (!(ssh->remote_bugs & BUG_SSH2_REKEY) && !ssh->bare_connection)\r
11660             ADD_SPECIALS(ssh2_rekey_special);\r
11661         if (ssh->mainchan)\r
11662             ADD_SPECIALS(ssh2_session_specials);\r
11664         if (ssh->n_uncert_hostkeys) {\r
11665             static const struct telnet_special uncert_start[] = {\r
11666                 {NULL, TS_SEP},\r
11667                 {"Cache new host key type", TS_SUBMENU},\r
11668             };\r
11669             static const struct telnet_special uncert_end[] = {\r
11670                 {NULL, TS_EXITMENU},\r
11671             };\r
11672             int i;\r
11674             ADD_SPECIALS(uncert_start);\r
11675             for (i = 0; i < ssh->n_uncert_hostkeys; i++) {\r
11676                 struct telnet_special uncert[1];\r
11677                 const struct ssh_signkey *alg =\r
11678                     hostkey_algs[ssh->uncert_hostkeys[i]].alg;\r
11679                 uncert[0].name = alg->name;\r
11680                 uncert[0].code = TS_LOCALSTART + ssh->uncert_hostkeys[i];\r
11681                 ADD_SPECIALS(uncert);\r
11682             }\r
11683             ADD_SPECIALS(uncert_end);\r
11684         }\r
11685     } /* else we're not ready yet */\r
11687     if (nspecials)\r
11688         ADD_SPECIALS(specials_end);\r
11690     ssh->specials = specials;\r
11692     if (nspecials) {\r
11693         return specials;\r
11694     } else {\r
11695         return NULL;\r
11696     }\r
11697 #undef ADD_SPECIALS\r
11700 /*\r
11701  * Send special codes. TS_EOF is useful for `plink', so you\r
11702  * can send an EOF and collect resulting output (e.g. `plink\r
11703  * hostname sort').\r
11704  */\r
11705 static void ssh_special(void *handle, Telnet_Special code)\r
11707     Ssh ssh = (Ssh) handle;\r
11708     struct Packet *pktout;\r
11710     if (code == TS_EOF) {\r
11711         if (ssh->state != SSH_STATE_SESSION) {\r
11712             /*\r
11713              * Buffer the EOF in case we are pre-SESSION, so we can\r
11714              * send it as soon as we reach SESSION.\r
11715              */\r
11716             if (code == TS_EOF)\r
11717                 ssh->eof_needed = TRUE;\r
11718             return;\r
11719         }\r
11720         if (ssh->version == 1) {\r
11721             send_packet(ssh, SSH1_CMSG_EOF, PKT_END);\r
11722         } else if (ssh->mainchan) {\r
11723             sshfwd_write_eof(ssh->mainchan);\r
11724             ssh->send_ok = 0;          /* now stop trying to read from stdin */\r
11725         }\r
11726         logevent("Sent EOF message");\r
11727     } else if (code == TS_PING || code == TS_NOP) {\r
11728         if (ssh->state == SSH_STATE_CLOSED\r
11729             || ssh->state == SSH_STATE_PREPACKET) return;\r
11730         if (ssh->version == 1) {\r
11731             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))\r
11732                 send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);\r
11733         } else {\r
11734             if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {\r
11735                 pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);\r
11736                 ssh2_pkt_addstring_start(pktout);\r
11737                 ssh2_pkt_send_noqueue(ssh, pktout);\r
11738             }\r
11739         }\r
11740     } else if (code == TS_REKEY) {\r
11741         if (!ssh->kex_in_progress && !ssh->bare_connection &&\r
11742             ssh->version == 2) {\r
11743             do_ssh2_transport(ssh, "at user request", -1, NULL);\r
11744         }\r
11745     } else if (code >= TS_LOCALSTART) {\r
11746         ssh->hostkey = hostkey_algs[code - TS_LOCALSTART].alg;\r
11747         ssh->cross_certifying = TRUE;\r
11748         if (!ssh->kex_in_progress && !ssh->bare_connection &&\r
11749             ssh->version == 2) {\r
11750             do_ssh2_transport(ssh, "cross-certifying new host key", -1, NULL);\r
11751         }\r
11752     } else if (code == TS_BRK) {\r
11753         if (ssh->state == SSH_STATE_CLOSED\r
11754             || ssh->state == SSH_STATE_PREPACKET) return;\r
11755         if (ssh->version == 1) {\r
11756             logevent("Unable to send BREAK signal in SSH-1");\r
11757         } else if (ssh->mainchan) {\r
11758             pktout = ssh2_chanreq_init(ssh->mainchan, "break", NULL, NULL);\r
11759             ssh2_pkt_adduint32(pktout, 0);   /* default break length */\r
11760             ssh2_pkt_send(ssh, pktout);\r
11761         }\r
11762     } else {\r
11763         /* Is is a POSIX signal? */\r
11764         const char *signame = NULL;\r
11765         if (code == TS_SIGABRT) signame = "ABRT";\r
11766         if (code == TS_SIGALRM) signame = "ALRM";\r
11767         if (code == TS_SIGFPE)  signame = "FPE";\r
11768         if (code == TS_SIGHUP)  signame = "HUP";\r
11769         if (code == TS_SIGILL)  signame = "ILL";\r
11770         if (code == TS_SIGINT)  signame = "INT";\r
11771         if (code == TS_SIGKILL) signame = "KILL";\r
11772         if (code == TS_SIGPIPE) signame = "PIPE";\r
11773         if (code == TS_SIGQUIT) signame = "QUIT";\r
11774         if (code == TS_SIGSEGV) signame = "SEGV";\r
11775         if (code == TS_SIGTERM) signame = "TERM";\r
11776         if (code == TS_SIGUSR1) signame = "USR1";\r
11777         if (code == TS_SIGUSR2) signame = "USR2";\r
11778         /* The SSH-2 protocol does in principle support arbitrary named\r
11779          * signals, including signame@domain, but we don't support those. */\r
11780         if (signame) {\r
11781             /* It's a signal. */\r
11782             if (ssh->version == 2 && ssh->mainchan) {\r
11783                 pktout = ssh2_chanreq_init(ssh->mainchan, "signal", NULL, NULL);\r
11784                 ssh2_pkt_addstring(pktout, signame);\r
11785                 ssh2_pkt_send(ssh, pktout);\r
11786                 logeventf(ssh, "Sent signal SIG%s", signame);\r
11787             }\r
11788         } else {\r
11789             /* Never heard of it. Do nothing */\r
11790         }\r
11791     }\r
11794 void *new_sock_channel(void *handle, struct PortForwarding *pf)\r
11796     Ssh ssh = (Ssh) handle;\r
11797     struct ssh_channel *c;\r
11798     c = snew(struct ssh_channel);\r
11800     c->ssh = ssh;\r
11801     ssh_channel_init(c);\r
11802     c->halfopen = TRUE;\r
11803     c->type = CHAN_SOCKDATA;/* identify channel type */\r
11804     c->u.pfd.pf = pf;\r
11805     return c;\r
11808 unsigned ssh_alloc_sharing_channel(Ssh ssh, void *sharing_ctx)\r
11810     struct ssh_channel *c;\r
11811     c = snew(struct ssh_channel);\r
11813     c->ssh = ssh;\r
11814     ssh_channel_init(c);\r
11815     c->type = CHAN_SHARING;\r
11816     c->u.sharing.ctx = sharing_ctx;\r
11817     return c->localid;\r
11820 void ssh_delete_sharing_channel(Ssh ssh, unsigned localid)\r
11822     struct ssh_channel *c;\r
11824     c = find234(ssh->channels, &localid, ssh_channelfind);\r
11825     if (c)\r
11826         ssh_channel_destroy(c);\r
11829 void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type,\r
11830                                      const void *data, int datalen,\r
11831                                      const char *additional_log_text)\r
11833     struct Packet *pkt;\r
11835     pkt = ssh2_pkt_init(type);\r
11836     pkt->downstream_id = id;\r
11837     pkt->additional_log_text = additional_log_text;\r
11838     ssh2_pkt_adddata(pkt, data, datalen);\r
11839     ssh2_pkt_send(ssh, pkt);\r
11842 /*\r
11843  * This is called when stdout/stderr (the entity to which\r
11844  * from_backend sends data) manages to clear some backlog.\r
11845  */\r
11846 static void ssh_unthrottle(void *handle, int bufsize)\r
11848     Ssh ssh = (Ssh) handle;\r
11850     if (ssh->version == 1) {\r
11851         if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {\r
11852             ssh->v1_stdout_throttling = 0;\r
11853             ssh_throttle_conn(ssh, -1);\r
11854         }\r
11855     } else {\r
11856         if (ssh->mainchan)\r
11857             ssh_channel_unthrottle(ssh->mainchan, bufsize);\r
11858     }\r
11860     /*\r
11861      * Now process any SSH connection data that was stashed in our\r
11862      * queue while we were frozen.\r
11863      */\r
11864     ssh_process_queued_incoming_data(ssh);\r
11867 void ssh_send_port_open(void *channel, const char *hostname, int port,\r
11868                         const char *org)\r
11870     struct ssh_channel *c = (struct ssh_channel *)channel;\r
11871     Ssh ssh = c->ssh;\r
11872     struct Packet *pktout;\r
11874     logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org);\r
11876     if (ssh->version == 1) {\r
11877         send_packet(ssh, SSH1_MSG_PORT_OPEN,\r
11878                     PKT_INT, c->localid,\r
11879                     PKT_STR, hostname,\r
11880                     PKT_INT, port,\r
11881                     /* PKT_STR, <org:orgport>, */\r
11882                     PKT_END);\r
11883     } else {\r
11884         pktout = ssh2_chanopen_init(c, "direct-tcpip");\r
11885         {\r
11886             char *trimmed_host = host_strduptrim(hostname);\r
11887             ssh2_pkt_addstring(pktout, trimmed_host);\r
11888             sfree(trimmed_host);\r
11889         }\r
11890         ssh2_pkt_adduint32(pktout, port);\r
11891         /*\r
11892          * We make up values for the originator data; partly it's\r
11893          * too much hassle to keep track, and partly I'm not\r
11894          * convinced the server should be told details like that\r
11895          * about my local network configuration.\r
11896          * The "originator IP address" is syntactically a numeric\r
11897          * IP address, and some servers (e.g., Tectia) get upset\r
11898          * if it doesn't match this syntax.\r
11899          */\r
11900         ssh2_pkt_addstring(pktout, "0.0.0.0");\r
11901         ssh2_pkt_adduint32(pktout, 0);\r
11902         ssh2_pkt_send(ssh, pktout);\r
11903     }\r
11906 static int ssh_connected(void *handle)\r
11908     Ssh ssh = (Ssh) handle;\r
11909     return ssh->s != NULL;\r
11912 static int ssh_sendok(void *handle)\r
11914     Ssh ssh = (Ssh) handle;\r
11915     return ssh->send_ok;\r
11918 static int ssh_ldisc(void *handle, int option)\r
11920     Ssh ssh = (Ssh) handle;\r
11921     if (option == LD_ECHO)\r
11922         return ssh->echoing;\r
11923     if (option == LD_EDIT)\r
11924         return ssh->editing;\r
11925     return FALSE;\r
11928 static void ssh_provide_ldisc(void *handle, void *ldisc)\r
11930     Ssh ssh = (Ssh) handle;\r
11931     ssh->ldisc = ldisc;\r
11934 static void ssh_provide_logctx(void *handle, void *logctx)\r
11936     Ssh ssh = (Ssh) handle;\r
11937     ssh->logctx = logctx;\r
11940 static int ssh_return_exitcode(void *handle)\r
11942     Ssh ssh = (Ssh) handle;\r
11943     if (ssh->s != NULL)\r
11944         return -1;\r
11945     else\r
11946         return (ssh->exitcode >= 0 ? ssh->exitcode : INT_MAX);\r
11949 /*\r
11950  * cfg_info for SSH is the protocol running in this session.\r
11951  * (1 or 2 for the full SSH-1 or SSH-2 protocol; -1 for the bare\r
11952  * SSH-2 connection protocol, i.e. a downstream; 0 for not-decided-yet.)\r
11953  */\r
11954 static int ssh_cfg_info(void *handle)\r
11956     Ssh ssh = (Ssh) handle;\r
11957     if (ssh->version == 0)\r
11958         return 0; /* don't know yet */\r
11959     else if (ssh->bare_connection)\r
11960         return -1;\r
11961     else\r
11962         return ssh->version;\r
11965 /*\r
11966  * Gross hack: pscp will try to start SFTP but fall back to scp1 if\r
11967  * that fails. This variable is the means by which scp.c can reach\r
11968  * into the SSH code and find out which one it got.\r
11969  */\r
11970 extern int ssh_fallback_cmd(void *handle)\r
11972     Ssh ssh = (Ssh) handle;\r
11973     return ssh->fallback_cmd;\r
11976 Backend ssh_backend = {\r
11977     ssh_init,\r
11978     ssh_free,\r
11979     ssh_reconfig,\r
11980     ssh_send,\r
11981     ssh_sendbuffer,\r
11982     ssh_size,\r
11983     ssh_special,\r
11984     ssh_get_specials,\r
11985     ssh_connected,\r
11986     ssh_return_exitcode,\r
11987     ssh_sendok,\r
11988     ssh_ldisc,\r
11989     ssh_provide_ldisc,\r
11990     ssh_provide_logctx,\r
11991     ssh_unthrottle,\r
11992     ssh_cfg_info,\r
11993     ssh_test_for_upstream,\r
11994     "ssh",\r
11995     PROT_SSH,\r
11996     22\r
11997 };\r