]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - ssh.c
Robert de Bath's Big Patch, part 1
[PuTTY.git] / ssh.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <assert.h>
5 #include <winsock.h>
6
7 #include "putty.h"
8 #include "ssh.h"
9 #include "scp.h"
10
11 #ifndef FALSE
12 #define FALSE 0
13 #endif
14 #ifndef TRUE
15 #define TRUE 1
16 #endif
17
18 #define logevent(s) { logevent(s); \
19                       if (IS_SCP && (scp_flags & SCP_VERBOSE) != 0) \
20                       fprintf(stderr, "%s\n", s); }
21
22 #define SSH_MSG_DISCONNECT      1
23 #define SSH_SMSG_PUBLIC_KEY     2
24 #define SSH_CMSG_SESSION_KEY    3
25 #define SSH_CMSG_USER           4
26 #define SSH_CMSG_AUTH_PASSWORD  9
27 #define SSH_CMSG_REQUEST_PTY    10
28 #define SSH_CMSG_WINDOW_SIZE    11
29 #define SSH_CMSG_EXEC_SHELL     12
30 #define SSH_CMSG_EXEC_CMD       13
31 #define SSH_SMSG_SUCCESS        14
32 #define SSH_SMSG_FAILURE        15
33 #define SSH_CMSG_STDIN_DATA     16
34 #define SSH_SMSG_STDOUT_DATA    17
35 #define SSH_SMSG_STDERR_DATA    18
36 #define SSH_CMSG_EOF            19
37 #define SSH_SMSG_EXIT_STATUS    20
38 #define SSH_CMSG_EXIT_CONFIRMATION      33
39 #define SSH_MSG_IGNORE          32
40 #define SSH_MSG_DEBUG           36
41 #define SSH_CMSG_AUTH_TIS       39
42 #define SSH_SMSG_AUTH_TIS_CHALLENGE     40
43 #define SSH_CMSG_AUTH_TIS_RESPONSE      41
44
45 #define SSH_AUTH_TIS            5
46
47 #define GET_32BIT(cp) \
48     (((unsigned long)(unsigned char)(cp)[0] << 24) | \
49     ((unsigned long)(unsigned char)(cp)[1] << 16) | \
50     ((unsigned long)(unsigned char)(cp)[2] << 8) | \
51     ((unsigned long)(unsigned char)(cp)[3]))
52
53 #define PUT_32BIT(cp, value) { \
54     (cp)[0] = (unsigned char)((value) >> 24); \
55     (cp)[1] = (unsigned char)((value) >> 16); \
56     (cp)[2] = (unsigned char)((value) >> 8); \
57     (cp)[3] = (unsigned char)(value); }
58
59 enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR };
60
61 /* Coroutine mechanics for the sillier bits of the code */
62 #define crBegin1        static int crLine = 0;
63 #define crBegin2        switch(crLine) { case 0:;
64 #define crBegin         crBegin1; crBegin2;
65 #define crFinish(z)     } crLine = 0; return (z)
66 #define crFinishV       } crLine = 0; return
67 #define crReturn(z)     \
68         do {\
69             crLine=__LINE__; return (z); case __LINE__:;\
70         } while (0)
71 #define crReturnV       \
72         do {\
73             crLine=__LINE__; return; case __LINE__:;\
74         } while (0)
75 #define crStop(z)       do{ crLine = 0; return (z); }while(0)
76 #define crStopV         do{ crLine = 0; return; }while(0)
77 #define crWaitUntil(c)  do { crReturn(0); } while (!(c))
78
79 static SOCKET s = INVALID_SOCKET;
80
81 static unsigned char session_key[32];
82 static struct ssh_cipher *cipher = NULL;
83 int scp_flags = 0;
84 int (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL;
85
86 static char *savedhost;
87
88 static enum {
89     SSH_STATE_BEFORE_SIZE,
90     SSH_STATE_INTERMED,
91     SSH_STATE_SESSION,
92     SSH_STATE_CLOSED
93 } ssh_state = SSH_STATE_BEFORE_SIZE;
94
95 static int size_needed = FALSE;
96
97 static void s_write (char *buf, int len) {
98     while (len > 0) {
99         int i = send (s, buf, len, 0);
100         if (IS_SCP) {
101             noise_ultralight(i);
102             if (i <= 0)
103                 fatalbox("Lost connection while sending");
104         }
105         if (i > 0)
106             len -= i, buf += i;
107     }
108 }
109
110 static int s_read (char *buf, int len) {
111     int ret = 0;
112     while (len > 0) {
113         int i = recv (s, buf, len, 0);
114         if (IS_SCP)
115             noise_ultralight(i);
116         if (i > 0)
117             len -= i, buf += i, ret += i;
118         else
119             return i;
120     }
121     return ret;
122 }
123
124 static void c_write (char *buf, int len) {
125     if (IS_SCP) {
126         if (len > 0 && buf[len-1] == '\n') len--;
127         if (len > 0 && buf[len-1] == '\r') len--;
128         if (len > 0) { fwrite(buf, len, 1, stderr); fputc('\n', stderr); }
129         return;
130     }
131     while (len--) 
132         c_write1(*buf++);
133 }
134
135 struct Packet {
136     long length;
137     int type;
138     unsigned char *data;
139     unsigned char *body;
140     long maxlen;
141 };
142
143 static struct Packet pktin = { 0, 0, NULL, NULL, 0 };
144 static struct Packet pktout = { 0, 0, NULL, NULL, 0 };
145
146 static void ssh_protocol(unsigned char *in, int inlen, int ispkt);
147 static void ssh_size(void);
148
149
150 /*
151  * Collect incoming data in the incoming packet buffer.
152  * Decihper and verify the packet when it is completely read.
153  * Drop SSH_MSG_DEBUG and SSH_MSG_IGNORE packets.
154  * Update the *data and *datalen variables.
155  * Return the additional nr of bytes needed, or 0 when
156  * a complete packet is available.
157  */
158 static int s_rdpkt(unsigned char **data, int *datalen)
159 {
160     static long len, pad, biglen, to_read;
161     static unsigned long realcrc, gotcrc;
162     static unsigned char *p;
163     static int i;
164
165     crBegin;
166
167 next_packet:
168
169     pktin.type = 0;
170     pktin.length = 0;
171
172     for (i = len = 0; i < 4; i++) {
173         while ((*datalen) == 0)
174             crReturn(4-i);
175         len = (len << 8) + **data;
176         (*data)++, (*datalen)--;
177     }
178
179 #ifdef FWHACK
180     if (len == 0x52656d6f) {       /* "Remo"te server has closed ... */
181         len = 0x300;               /* big enough to carry to end */
182     }
183 #endif
184
185     pad = 8 - (len % 8);
186     biglen = len + pad;
187     pktin.length = len - 5;
188
189     if (pktin.maxlen < biglen) {
190         pktin.maxlen = biglen;
191 #ifdef MSCRYPTOAPI
192         /* Allocate enough buffer space for extra block
193          * for MS CryptEncrypt() */
194         pktin.data = (pktin.data == NULL ? malloc(biglen+8) :
195                       realloc(pktin.data, biglen+8));
196 #else
197         pktin.data = (pktin.data == NULL ? malloc(biglen) :
198                       realloc(pktin.data, biglen));
199 #endif
200         if (!pktin.data)
201             fatalbox("Out of memory");
202     }
203
204     to_read = biglen;
205     p = pktin.data;
206     while (to_read > 0) {
207         static int chunk;
208         chunk = to_read;
209         while ((*datalen) == 0)
210             crReturn(to_read);
211         if (chunk > (*datalen))
212             chunk = (*datalen);
213         memcpy(p, *data, chunk);
214         *data += chunk;
215         *datalen -= chunk;
216         p += chunk;
217         to_read -= chunk;
218     }
219
220     if (cipher)
221         cipher->decrypt(pktin.data, biglen);
222
223     pktin.type = pktin.data[pad];
224     pktin.body = pktin.data + pad + 1;
225
226     realcrc = crc32(pktin.data, biglen-4);
227     gotcrc = GET_32BIT(pktin.data+biglen-4);
228     if (gotcrc != realcrc) {
229         fatalbox("Incorrect CRC received on packet");
230     }
231
232     if (pktin.type == SSH_SMSG_STDOUT_DATA ||
233         pktin.type == SSH_SMSG_STDERR_DATA ||
234         pktin.type == SSH_MSG_DEBUG ||
235         pktin.type == SSH_SMSG_AUTH_TIS_CHALLENGE) {
236         long strlen = GET_32BIT(pktin.body);
237         if (strlen + 4 != pktin.length)
238             fatalbox("Received data packet with bogus string length");
239     }
240
241     if (pktin.type == SSH_MSG_DEBUG) {
242         /* log debug message */
243         char buf[80];
244         int strlen = GET_32BIT(pktin.body);
245         strcpy(buf, "Remote: ");
246         if (strlen > 70) strlen = 70;
247         memcpy(buf+8, pktin.body+4, strlen);
248         buf[8+strlen] = '\0';
249         logevent(buf);
250         goto next_packet;
251     } else if (pktin.type == SSH_MSG_IGNORE) {
252         /* do nothing */
253         goto next_packet;
254     }
255
256     crFinish(0);
257 }
258
259 static void ssh_gotdata(unsigned char *data, int datalen)
260 {
261     while (datalen > 0) {
262         if ( s_rdpkt(&data, &datalen) == 0 ) {
263             ssh_protocol(NULL, 0, 1);
264             if (ssh_state == SSH_STATE_CLOSED) {
265                 return;
266             }
267         }
268     }
269 }
270
271
272 static void s_wrpkt_start(int type, int len) {
273     int pad, biglen;
274
275     len += 5;                          /* type and CRC */
276     pad = 8 - (len%8);
277     biglen = len + pad;
278
279     pktout.length = len-5;
280     if (pktout.maxlen < biglen) {
281         pktout.maxlen = biglen;
282 #ifdef MSCRYPTOAPI
283         /* Allocate enough buffer space for extra block
284          * for MS CryptEncrypt() */
285         pktout.data = (pktout.data == NULL ? malloc(biglen+12) :
286                        realloc(pktout.data, biglen+12));
287 #else
288         pktout.data = (pktout.data == NULL ? malloc(biglen+4) :
289                        realloc(pktout.data, biglen+4));
290 #endif
291         if (!pktout.data)
292             fatalbox("Out of memory");
293     }
294
295     pktout.type = type;
296     pktout.body = pktout.data+4+pad+1;
297 }
298
299 static void s_wrpkt(void) {
300     int pad, len, biglen, i;
301     unsigned long crc;
302
303     len = pktout.length + 5;           /* type and CRC */
304     pad = 8 - (len%8);
305     biglen = len + pad;
306
307     pktout.body[-1] = pktout.type;
308     for (i=0; i<pad; i++)
309         pktout.data[i+4] = random_byte();
310     crc = crc32(pktout.data+4, biglen-4);
311     PUT_32BIT(pktout.data+biglen, crc);
312     PUT_32BIT(pktout.data, len);
313
314     if (cipher)
315         cipher->encrypt(pktout.data+4, biglen);
316
317     s_write(pktout.data, biglen+4);
318 }
319
320 /*
321  * Construct a packet with the specified contents and
322  * send it to the server.
323  */
324 static void send_packet(int pkttype, ...)
325 {
326     va_list args;
327     unsigned char *p, *argp, argchar;
328     unsigned long argint;
329     int pktlen, argtype, arglen;
330
331     pktlen = 0;
332     va_start(args, pkttype);
333     while ((argtype = va_arg(args, int)) != PKT_END) {
334         switch (argtype) {
335           case PKT_INT:
336             (void) va_arg(args, int);
337             pktlen += 4;
338             break;
339           case PKT_CHAR:
340             (void) va_arg(args, char);
341             pktlen++;
342             break;
343           case PKT_DATA:
344             (void) va_arg(args, unsigned char *);
345             arglen = va_arg(args, int);
346             pktlen += arglen;
347             break;
348           case PKT_STR:
349             argp = va_arg(args, unsigned char *);
350             arglen = strlen(argp);
351             pktlen += 4 + arglen;
352             break;
353           default:
354             assert(0);
355         }
356     }
357     va_end(args);
358
359     s_wrpkt_start(pkttype, pktlen);
360     p = pktout.body;
361
362     va_start(args, pkttype);
363     while ((argtype = va_arg(args, int)) != PKT_END) {
364         switch (argtype) {
365           case PKT_INT:
366             argint = va_arg(args, int);
367             PUT_32BIT(p, argint);
368             p += 4;
369             break;
370           case PKT_CHAR:
371             argchar = va_arg(args, unsigned char);
372             *p = argchar;
373             p++;
374             break;
375           case PKT_DATA:
376             argp = va_arg(args, unsigned char *);
377             arglen = va_arg(args, int);
378             memcpy(p, argp, arglen);
379             p += arglen;
380             break;
381           case PKT_STR:
382             argp = va_arg(args, unsigned char *);
383             arglen = strlen(argp);
384             PUT_32BIT(p, arglen);
385             memcpy(p + 4, argp, arglen);
386             p += 4 + arglen;
387             break;
388         }
389     }
390     va_end(args);
391
392     s_wrpkt();
393 }
394
395
396 /*
397  * Connect to specified host and port.
398  * Returns an error message, or NULL on success.
399  * Also places the canonical host name into `realhost'.
400  */
401 static char *connect_to_host(char *host, int port, char **realhost)
402 {
403     SOCKADDR_IN addr;
404     struct hostent *h;
405     unsigned long a;
406 #ifdef FWHACK
407     char *FWhost;
408     int FWport;
409 #endif
410
411     savedhost = malloc(1+strlen(host));
412     if (!savedhost)
413         fatalbox("Out of memory");
414     strcpy(savedhost, host);
415
416     if (port < 0)
417         port = 22;                     /* default ssh port */
418
419 #ifdef FWHACK
420     FWhost = host;
421     FWport = port;
422     host = FWSTR;
423     port = 23;
424 #endif
425
426     /*
427      * Try to find host.
428      */
429     if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
430         if ( (h = gethostbyname(host)) == NULL)
431             switch (WSAGetLastError()) {
432               case WSAENETDOWN: return "Network is down";
433               case WSAHOST_NOT_FOUND: case WSANO_DATA:
434                 return "Host does not exist";
435               case WSATRY_AGAIN: return "Host not found";
436               default: return "gethostbyname: unknown error";
437             }
438         memcpy (&a, h->h_addr, sizeof(a));
439         *realhost = h->h_name;
440     } else
441         *realhost = host;
442 #ifdef FWHACK
443     *realhost = FWhost;
444 #endif
445     a = ntohl(a);
446
447     /*
448      * Open socket.
449      */
450     s = socket(AF_INET, SOCK_STREAM, 0);
451     if (s == INVALID_SOCKET)
452         switch (WSAGetLastError()) {
453           case WSAENETDOWN: return "Network is down";
454           case WSAEAFNOSUPPORT: return "TCP/IP support not present";
455           default: return "socket(): unknown error";
456         }
457
458     /*
459      * Bind to local address.
460      */
461     addr.sin_family = AF_INET;
462     addr.sin_addr.s_addr = htonl(INADDR_ANY);
463     addr.sin_port = htons(0);
464     if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
465         switch (WSAGetLastError()) {
466           case WSAENETDOWN: return "Network is down";
467           default: return "bind(): unknown error";
468         }
469
470     /*
471      * Connect to remote address.
472      */
473     addr.sin_addr.s_addr = htonl(a);
474     addr.sin_port = htons((short)port);
475     if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
476         switch (WSAGetLastError()) {
477           case WSAENETDOWN: return "Network is down";
478           case WSAECONNREFUSED: return "Connection refused";
479           case WSAENETUNREACH: return "Network is unreachable";
480           case WSAEHOSTUNREACH: return "No route to host";
481           default: return "connect(): unknown error";
482         }
483
484 #ifdef FWHACK
485     send(s, "connect ", 8, 0);
486     send(s, FWhost, strlen(FWhost), 0);
487     {
488         char buf[20];
489         sprintf(buf, " %d\n", FWport);
490         send (s, buf, strlen(buf), 0);
491     }
492 #endif
493
494     return NULL;
495 }
496
497 static int ssh_versioncmp(char *a, char *b) {
498     char *ae, *be;
499     unsigned long av, bv;
500
501     av = strtoul(a, &ae, 10);
502     bv = strtoul(b, &be, 10);
503     if (av != bv) return (av < bv ? -1 : +1);
504     if (*ae == '.') ae++;
505     if (*be == '.') be++;
506     av = strtoul(ae, &ae, 10);
507     bv = strtoul(be, &be, 10);
508     if (av != bv) return (av < bv ? -1 : +1);
509     return 0;
510 }
511
512 static int do_ssh_init(void) {
513     char c, *vsp;
514     char version[10];
515     char vstring[80];
516     char vlog[sizeof(vstring)+20];
517     int i;
518
519 #ifdef FWHACK
520     i = 0;
521     while (s_read(&c, 1) == 1) {
522         if (c == 'S' && i < 2) i++;
523         else if (c == 'S' && i == 2) i = 2;
524         else if (c == 'H' && i == 2) break;
525         else i = 0;
526     }
527 #else
528     if (s_read(&c,1) != 1 || c != 'S') return 0;
529     if (s_read(&c,1) != 1 || c != 'S') return 0;
530     if (s_read(&c,1) != 1 || c != 'H') return 0;
531 #endif
532     strcpy(vstring, "SSH-");
533     vsp = vstring+4;
534     if (s_read(&c,1) != 1 || c != '-') return 0;
535     i = 0;
536     while (1) {
537         if (s_read(&c,1) != 1)
538             return 0;
539         if (vsp < vstring+sizeof(vstring)-1)
540             *vsp++ = c;
541         if (i >= 0) {
542             if (c == '-') {
543                 version[i] = '\0';
544                 i = -1;
545             } else if (i < sizeof(version)-1)
546                 version[i++] = c;
547         }
548         else if (c == '\n')
549             break;
550     }
551
552     *vsp = 0;
553     sprintf(vlog, "Server version: %s", vstring);
554     vlog[strcspn(vlog, "\r\n")] = '\0';
555     logevent(vlog);
556
557     sprintf(vstring, "SSH-%s-PuTTY\n",
558             (ssh_versioncmp(version, "1.5") <= 0 ? version : "1.5"));
559     sprintf(vlog, "We claim version: %s", vstring);
560     vlog[strcspn(vlog, "\r\n")] = '\0';
561     logevent(vlog);
562     s_write(vstring, strlen(vstring));
563     return 1;
564 }
565
566 /*
567  * Handle the key exchange and user authentication phases.
568  */
569 static int do_ssh_login(unsigned char *in, int inlen, int ispkt)
570 {
571     int i, j, len;
572     unsigned char session_id[16];
573     unsigned char *rsabuf, *keystr1, *keystr2;
574     unsigned char cookie[8];
575     struct RSAKey servkey, hostkey;
576     struct MD5Context md5c;
577     static unsigned long supported_ciphers_mask, supported_auths_mask;
578     int cipher_type;
579
580     extern struct ssh_cipher ssh_3des;
581     extern struct ssh_cipher ssh_des;
582     extern struct ssh_cipher ssh_blowfish;
583
584     crBegin;
585
586     if (!ispkt) crWaitUntil(ispkt);
587
588     if (pktin.type != SSH_SMSG_PUBLIC_KEY)
589         fatalbox("Public key packet not received");
590
591     logevent("Received public keys");
592
593     memcpy(cookie, pktin.body, 8);
594
595     i = makekey(pktin.body+8, &servkey, &keystr1);
596     j = makekey(pktin.body+8+i, &hostkey, &keystr2);
597
598     /*
599      * Hash the host key and print the hash in the log box. Just as
600      * a last resort in case the registry's host key checking is
601      * compromised, we'll allow the user some ability to verify
602      * host keys by eye.
603      */
604     MD5Init(&md5c);
605     MD5Update(&md5c, keystr2, hostkey.bytes);
606     MD5Final(session_id, &md5c);
607     {
608         char logmsg[80];
609         int i;
610         logevent("Host key MD5 is:");
611         strcpy(logmsg, "      ");
612         for (i = 0; i < 16; i++)
613             sprintf(logmsg+strlen(logmsg), "%02x", session_id[i]);
614         logevent(logmsg);
615     }
616
617     supported_ciphers_mask = GET_32BIT(pktin.body+12+i+j);
618     supported_auths_mask = GET_32BIT(pktin.body+16+i+j);
619
620     MD5Init(&md5c);
621     MD5Update(&md5c, keystr2, hostkey.bytes);
622     MD5Update(&md5c, keystr1, servkey.bytes);
623     MD5Update(&md5c, pktin.body, 8);
624     MD5Final(session_id, &md5c);
625
626     for (i=0; i<32; i++)
627         session_key[i] = random_byte();
628
629     len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
630
631     rsabuf = malloc(len);
632     if (!rsabuf)
633         fatalbox("Out of memory");
634
635     /*
636      * Verify the host key.
637      */
638     {
639         /*
640          * First format the key into a string.
641          */
642         int len = rsastr_len(&hostkey);
643         char *keystr = malloc(len);
644         if (!keystr)
645             fatalbox("Out of memory");
646         rsastr_fmt(keystr, &hostkey);
647         verify_ssh_host_key(savedhost, keystr);
648         free(keystr);
649     }
650
651     for (i=0; i<32; i++) {
652         rsabuf[i] = session_key[i];
653         if (i < 16)
654             rsabuf[i] ^= session_id[i];
655     }
656
657     if (hostkey.bytes > servkey.bytes) {
658         rsaencrypt(rsabuf, 32, &servkey);
659         rsaencrypt(rsabuf, servkey.bytes, &hostkey);
660     } else {
661         rsaencrypt(rsabuf, 32, &hostkey);
662         rsaencrypt(rsabuf, hostkey.bytes, &servkey);
663     }
664
665     logevent("Encrypted session key");
666
667     cipher_type = cfg.cipher == CIPHER_BLOWFISH ? SSH_CIPHER_BLOWFISH :
668                   cfg.cipher == CIPHER_DES ? SSH_CIPHER_DES : 
669                   SSH_CIPHER_3DES;
670     if ((supported_ciphers_mask & (1 << cipher_type)) == 0) {
671         c_write("Selected cipher not supported, falling back to 3DES\r\n", 53);
672         cipher_type = SSH_CIPHER_3DES;
673     }
674     switch (cipher_type) {
675       case SSH_CIPHER_3DES: logevent("Using 3DES encryption"); break;
676       case SSH_CIPHER_DES: logevent("Using single-DES encryption"); break;
677       case SSH_CIPHER_BLOWFISH: logevent("Using Blowfish encryption"); break;
678     }
679
680     send_packet(SSH_CMSG_SESSION_KEY,
681                 PKT_CHAR, cipher_type,
682                 PKT_DATA, cookie, 8,
683                 PKT_CHAR, (len*8) >> 8, PKT_CHAR, (len*8) & 0xFF,
684                 PKT_DATA, rsabuf, len,
685                 PKT_INT, 0,
686                 PKT_END);
687
688     logevent("Trying to enable encryption...");
689
690     free(rsabuf);
691
692     cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish :
693              cipher_type == SSH_CIPHER_DES ? &ssh_des :
694              &ssh_3des;
695     cipher->sesskey(session_key);
696
697     crWaitUntil(ispkt);
698
699     if (pktin.type != SSH_SMSG_SUCCESS)
700         fatalbox("Encryption not successfully enabled");
701
702     logevent("Successfully started encryption");
703
704     fflush(stdout);
705     {
706         static char username[100];
707         static int pos = 0;
708         static char c;
709         if (!IS_SCP && !*cfg.username) {
710             c_write("login as: ", 10);
711             while (pos >= 0) {
712                 crWaitUntil(!ispkt);
713                 while (inlen--) switch (c = *in++) {
714                   case 10: case 13:
715                     username[pos] = 0;
716                     pos = -1;
717                     break;
718                   case 8: case 127:
719                     if (pos > 0) {
720                         c_write("\b \b", 3);
721                         pos--;
722                     }
723                     break;
724                   case 21: case 27:
725                     while (pos > 0) {
726                         c_write("\b \b", 3);
727                         pos--;
728                     }
729                     break;
730                   case 3: case 4:
731                     random_save_seed();
732                     exit(0);
733                     break;
734                   default:
735                     if (((c >= ' ' && c <= '~') ||
736                          ((unsigned char)c >= 160)) && pos < 40) {
737                         username[pos++] = c;
738                         c_write(&c, 1);
739                     }
740                     break;
741                 }
742             }
743             c_write("\r\n", 2);
744             username[strcspn(username, "\n\r")] = '\0';
745         } else {
746             char stuff[200];
747             strncpy(username, cfg.username, 99);
748             username[99] = '\0';
749             if (!IS_SCP) {
750                 sprintf(stuff, "Sent username \"%s\".\r\n", username);
751                 c_write(stuff, strlen(stuff));
752             }
753         }
754
755         send_packet(SSH_CMSG_USER, PKT_STR, username, PKT_END);
756         {
757             char userlog[20+sizeof(username)];
758             sprintf(userlog, "Sent username \"%s\"", username);
759             logevent(userlog);
760         }
761     }
762
763     crWaitUntil(ispkt);
764
765     while (pktin.type == SSH_SMSG_FAILURE) {
766         static char password[100];
767         static int pos;
768         static char c;
769         static int pwpkt_type;
770
771         /*
772          * Show password prompt, having first obtained it via a TIS
773          * exchange if we're doing TIS authentication.
774          */
775         pwpkt_type = SSH_CMSG_AUTH_PASSWORD;
776
777         if (IS_SCP) {
778             char prompt[200];
779             sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
780             if (!ssh_get_password(prompt, password, sizeof(password))) {
781                 /*
782                  * get_password failed to get a password (for
783                  * example because one was supplied on the command
784                  * line which has already failed to work).
785                  * Terminate.
786                  */
787                 logevent("No more passwords to try");
788                 ssh_state = SSH_STATE_CLOSED;
789                 crReturn(1);
790             }
791         } else {
792
793         if (pktin.type == SSH_SMSG_FAILURE &&
794             cfg.try_tis_auth &&
795             (supported_auths_mask & (1<<SSH_AUTH_TIS))) {
796             pwpkt_type = SSH_CMSG_AUTH_TIS_RESPONSE;
797             logevent("Requested TIS authentication");
798             send_packet(SSH_CMSG_AUTH_TIS, PKT_END);
799             crWaitUntil(ispkt);
800             if (pktin.type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
801                 logevent("TIS authentication declined");
802                 c_write("TIS authentication refused.\r\n", 29);
803             } else {
804                 int challengelen = ((pktin.body[0] << 24) |
805                                     (pktin.body[1] << 16) |
806                                     (pktin.body[2] << 8) |
807                                     (pktin.body[3]));
808                 logevent("Received TIS challenge");
809                 c_write(pktin.body+4, challengelen);
810             }
811         }
812         if (pwpkt_type == SSH_CMSG_AUTH_PASSWORD)
813             c_write("password: ", 10);
814
815         pos = 0;
816         while (pos >= 0) {
817             crWaitUntil(!ispkt);
818             while (inlen--) switch (c = *in++) {
819               case 10: case 13:
820                 password[pos] = 0;
821                 pos = -1;
822                 break;
823               case 8: case 127:
824                 if (pos > 0)
825                     pos--;
826                 break;
827               case 21: case 27:
828                 pos = 0;
829                 break;
830               case 3: case 4:
831                 random_save_seed();
832                 exit(0);
833                 break;
834               default:
835                 if (((c >= ' ' && c <= '~') ||
836                      ((unsigned char)c >= 160)) && pos < 40)
837                     password[pos++] = c;
838                 break;
839             }
840         }
841         c_write("\r\n", 2);
842
843         }
844
845         send_packet(pwpkt_type, PKT_STR, password, PKT_END);
846         logevent("Sent password");
847         memset(password, 0, strlen(password));
848         crWaitUntil(ispkt);
849         if (pktin.type == SSH_SMSG_FAILURE) {
850             c_write("Access denied\r\n", 15);
851             logevent("Authentication refused");
852         } else if (pktin.type == SSH_MSG_DISCONNECT) {
853             logevent("Received disconnect request");
854             ssh_state = SSH_STATE_CLOSED;
855             crReturn(1);
856         } else if (pktin.type != SSH_SMSG_SUCCESS) {
857             fatalbox("Strange packet received, type %d", pktin.type);
858         }
859     }
860
861     logevent("Authentication successful");
862
863     crFinish(1);
864 }
865
866 static void ssh_protocol(unsigned char *in, int inlen, int ispkt) {
867     crBegin;
868
869     random_init();
870
871     while (!do_ssh_login(in, inlen, ispkt)) {
872         crReturnV;
873     }
874     if (ssh_state == SSH_STATE_CLOSED)
875         crReturnV;
876
877     if (!cfg.nopty) {
878         send_packet(SSH_CMSG_REQUEST_PTY,
879                     PKT_STR, cfg.termtype,
880                     PKT_INT, rows, PKT_INT, cols,
881                     PKT_INT, 0, PKT_INT, 0,
882                     PKT_CHAR, 0,
883                     PKT_END);
884         ssh_state = SSH_STATE_INTERMED;
885         do { crReturnV; } while (!ispkt);
886         if (pktin.type != SSH_SMSG_SUCCESS && pktin.type != SSH_SMSG_FAILURE) {
887             fatalbox("Protocol confusion");
888         } else if (pktin.type == SSH_SMSG_FAILURE) {
889             c_write("Server refused to allocate pty\r\n", 32);
890         }
891         logevent("Allocated pty");
892     }
893
894     send_packet(SSH_CMSG_EXEC_SHELL, PKT_END);
895     logevent("Started session");
896
897     ssh_state = SSH_STATE_SESSION;
898     if (size_needed)
899         ssh_size();
900
901     while (1) {
902         crReturnV;
903         if (ispkt) {
904             if (pktin.type == SSH_SMSG_STDOUT_DATA ||
905                 pktin.type == SSH_SMSG_STDERR_DATA) {
906                 long len = GET_32BIT(pktin.body);
907                 c_write(pktin.body+4, len);
908             } else if (pktin.type == SSH_MSG_DISCONNECT) {
909                 ssh_state = SSH_STATE_CLOSED;
910                 logevent("Received disconnect request");
911             } else if (pktin.type == SSH_SMSG_SUCCESS) {
912                 /* may be from EXEC_SHELL on some servers */
913             } else if (pktin.type == SSH_SMSG_FAILURE) {
914                 /* may be from EXEC_SHELL on some servers
915                  * if no pty is available or in other odd cases. Ignore */
916             } else if (pktin.type == SSH_SMSG_EXIT_STATUS) {
917                 send_packet(SSH_CMSG_EXIT_CONFIRMATION, PKT_END);
918             } else {
919                 fatalbox("Strange packet received: type %d", pktin.type);
920             }
921         } else {
922             send_packet(SSH_CMSG_STDIN_DATA,
923                         PKT_INT, inlen, PKT_DATA, in, inlen, PKT_END);
924         }
925     }
926
927     crFinishV;
928 }
929
930 /*
931  * Called to set up the connection. Will arrange for WM_NETEVENT
932  * messages to be passed to the specified window, whose window
933  * procedure should then call telnet_msg().
934  *
935  * Returns an error message, or NULL on success.
936  */
937 static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
938     char *p;
939         
940 #ifdef MSCRYPTOAPI
941     if(crypto_startup() == 0)
942         return "Microsoft high encryption pack not installed!";
943 #endif
944
945     p = connect_to_host(host, port, realhost);
946     if (p != NULL)
947         return p;
948
949     if (!do_ssh_init())
950         return "Protocol initialisation error";
951
952     if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
953         switch (WSAGetLastError()) {
954           case WSAENETDOWN: return "Network is down";
955           default: return "WSAAsyncSelect(): unknown error";
956         }
957
958     return NULL;
959 }
960
961 /*
962  * Process a WM_NETEVENT message. Will return 0 if the connection
963  * has closed, or <0 for a socket error.
964  */
965 static int ssh_msg (WPARAM wParam, LPARAM lParam) {
966     int ret;
967     char buf[256];
968
969     /*
970      * Because reading less than the whole of the available pending
971      * data can generate an FD_READ event, we need to allow for the
972      * possibility that FD_READ may arrive with FD_CLOSE already in
973      * the queue; so it's possible that we can get here even with s
974      * invalid. If so, we return 1 and don't worry about it.
975      */
976     if (s == INVALID_SOCKET)
977         return 1;
978
979     if (WSAGETSELECTERROR(lParam) != 0)
980         return -WSAGETSELECTERROR(lParam);
981
982     switch (WSAGETSELECTEVENT(lParam)) {
983       case FD_READ:
984       case FD_CLOSE:
985         ret = recv(s, buf, sizeof(buf), 0);
986         if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
987             return 1;
988         if (ret < 0)                   /* any _other_ error */
989             return -10000-WSAGetLastError();
990         if (ret == 0) {
991             s = INVALID_SOCKET;
992             return 0;
993         }
994         ssh_gotdata (buf, ret);
995         if (ssh_state == SSH_STATE_CLOSED) {
996             closesocket(s);
997             s = INVALID_SOCKET;
998             return 0;
999         }
1000         return 1;
1001     }
1002     return 1;                          /* shouldn't happen, but WTF */
1003 }
1004
1005 /*
1006  * Called to send data down the Telnet connection.
1007  */
1008 static void ssh_send (char *buf, int len) {
1009     if (s == INVALID_SOCKET)
1010         return;
1011
1012     ssh_protocol(buf, len, 0);
1013 }
1014
1015 /*
1016  * Called to set the size of the window from Telnet's POV.
1017  */
1018 static void ssh_size(void) {
1019     switch (ssh_state) {
1020       case SSH_STATE_BEFORE_SIZE:
1021       case SSH_STATE_CLOSED:
1022         break;                         /* do nothing */
1023       case SSH_STATE_INTERMED:
1024         size_needed = TRUE;            /* buffer for later */
1025         break;
1026       case SSH_STATE_SESSION:
1027         if (!cfg.nopty) {
1028             send_packet(SSH_CMSG_WINDOW_SIZE,
1029                         PKT_INT, rows, PKT_INT, cols,
1030                         PKT_INT, 0, PKT_INT, 0, PKT_END);
1031         }
1032     }
1033 }
1034
1035 /*
1036  * (Send Telnet special codes)
1037  */
1038 static void ssh_special (Telnet_Special code) {
1039     /* do nothing */
1040 }
1041
1042
1043 /*
1044  * Read and decrypt one incoming SSH packet.
1045  * (only used by pSCP)
1046  */
1047 static void get_packet(void)
1048 {
1049     unsigned char buf[4096], *p;
1050     long to_read;
1051     int len;
1052
1053     assert(IS_SCP);
1054
1055     p = NULL;
1056     len = 0;
1057
1058     while ((to_read = s_rdpkt(&p, &len)) > 0) {
1059         if (to_read > sizeof(buf)) to_read = sizeof(buf);
1060         len = s_read(buf, to_read);
1061         if (len != to_read) {
1062             closesocket(s);
1063             s = INVALID_SOCKET;
1064             return;
1065         }
1066         p = buf;
1067     }
1068
1069     assert(len == 0);
1070 }
1071
1072 /*
1073  * Receive a block of data over the SSH link. Block until
1074  * all data is available. Return nr of bytes read (0 if lost connection).
1075  * (only used by pSCP)
1076  */
1077 int ssh_scp_recv(unsigned char *buf, int len)
1078 {
1079     static int pending_input_len = 0;
1080     static unsigned char *pending_input_ptr;
1081     int to_read = len;
1082
1083     assert(IS_SCP);
1084
1085     if (pending_input_len >= to_read) {
1086         memcpy(buf, pending_input_ptr, to_read);
1087         pending_input_ptr += to_read;
1088         pending_input_len -= to_read;
1089         return len;
1090     }
1091     
1092     if (pending_input_len > 0) {
1093         memcpy(buf, pending_input_ptr, pending_input_len);
1094         buf += pending_input_len;
1095         to_read -= pending_input_len;
1096         pending_input_len = 0;
1097     }
1098
1099     if (s == INVALID_SOCKET)
1100         return 0;
1101     while (to_read > 0) {
1102         get_packet();
1103         if (s == INVALID_SOCKET)
1104             return 0;
1105         if (pktin.type == SSH_SMSG_STDOUT_DATA) {
1106             int plen = GET_32BIT(pktin.body);
1107             if (plen <= to_read) {
1108                 memcpy(buf, pktin.body + 4, plen);
1109                 buf += plen;
1110                 to_read -= plen;
1111             } else {
1112                 memcpy(buf, pktin.body + 4, to_read);
1113                 pending_input_len = plen - to_read;
1114                 pending_input_ptr = pktin.body + 4 + to_read;
1115                 to_read = 0;
1116             }
1117         } else if (pktin.type == SSH_SMSG_STDERR_DATA) {
1118             int plen = GET_32BIT(pktin.body);
1119             fwrite(pktin.body + 4, plen, 1, stderr);
1120         } else if (pktin.type == SSH_MSG_DISCONNECT) {
1121                 logevent("Received disconnect request");
1122         } else if (pktin.type == SSH_SMSG_SUCCESS ||
1123                    pktin.type == SSH_SMSG_FAILURE) {
1124                 /* ignore */
1125         } else if (pktin.type == SSH_SMSG_EXIT_STATUS) {
1126             char logbuf[100];
1127             sprintf(logbuf, "Remote exit status: %d", GET_32BIT(pktin.body));
1128             logevent(logbuf);
1129             send_packet(SSH_CMSG_EXIT_CONFIRMATION, PKT_END);
1130             logevent("Closing connection");
1131             closesocket(s);
1132             s = INVALID_SOCKET;
1133         } else {
1134             fatalbox("Strange packet received: type %d", pktin.type);
1135         }
1136     }
1137
1138     return len;
1139 }
1140
1141 /*
1142  * Send a block of data over the SSH link.
1143  * Block until all data is sent.
1144  * (only used by pSCP)
1145  */
1146 void ssh_scp_send(unsigned char *buf, int len)
1147 {
1148     assert(IS_SCP);
1149     if (s == INVALID_SOCKET)
1150         return;
1151     send_packet(SSH_CMSG_STDIN_DATA,
1152                 PKT_INT, len, PKT_DATA, buf, len, PKT_END);
1153 }
1154
1155 /*
1156  * Send an EOF notification to the server.
1157  * (only used by pSCP)
1158  */
1159 void ssh_scp_send_eof(void)
1160 {
1161     assert(IS_SCP);
1162     if (s == INVALID_SOCKET)
1163         return;
1164     send_packet(SSH_CMSG_EOF, PKT_END);
1165 }
1166
1167 /*
1168  * Set up the connection, login on the remote host and
1169  * start execution of a command.
1170  * Returns an error message, or NULL on success.
1171  * (only used by pSCP)
1172  */
1173 char *ssh_scp_init(char *host, int port, char *cmd, char **realhost)
1174 {
1175     char buf[160], *p;
1176
1177     assert(IS_SCP);
1178
1179 #ifdef MSCRYPTOAPI
1180     if (crypto_startup() == 0)
1181         return "Microsoft high encryption pack not installed!";
1182 #endif
1183
1184     p = connect_to_host(host, port, realhost);
1185     if (p != NULL)
1186         return p;
1187
1188     random_init();
1189
1190     if (!do_ssh_init())
1191         return "Protocol initialisation error";
1192
1193     /* Exchange keys and login */
1194     do {
1195         get_packet();
1196         if (s == INVALID_SOCKET)
1197             return "Connection closed by remote host";
1198     } while (!do_ssh_login(NULL, 0, 1));
1199
1200     if (ssh_state == SSH_STATE_CLOSED) {
1201         closesocket(s);
1202         s = INVALID_SOCKET;
1203         return "Session initialisation error";
1204     }
1205
1206     /* Execute command */
1207     sprintf(buf, "Sending command: %.100s", cmd);
1208     logevent(buf);
1209     send_packet(SSH_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);
1210
1211     return NULL;
1212 }
1213
1214
1215 Backend ssh_backend = {
1216     ssh_init,
1217     ssh_msg,
1218     ssh_send,
1219     ssh_size,
1220     ssh_special
1221 };
1222