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