]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - portfwd.c
`dynamic' was uninitialised in other types of port forwarding. Oops.
[PuTTY.git] / portfwd.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include "putty.h"
5 #include "ssh.h"
6
7 #ifndef FALSE
8 #define FALSE 0
9 #endif
10 #ifndef TRUE
11 #define TRUE 1
12 #endif
13
14 #define GET_32BIT_LSB_FIRST(cp) \
15   (((unsigned long)(unsigned char)(cp)[0]) | \
16   ((unsigned long)(unsigned char)(cp)[1] << 8) | \
17   ((unsigned long)(unsigned char)(cp)[2] << 16) | \
18   ((unsigned long)(unsigned char)(cp)[3] << 24))
19
20 #define PUT_32BIT_LSB_FIRST(cp, value) ( \
21   (cp)[0] = (value), \
22   (cp)[1] = (value) >> 8, \
23   (cp)[2] = (value) >> 16, \
24   (cp)[3] = (value) >> 24 )
25
26 #define GET_16BIT_LSB_FIRST(cp) \
27   (((unsigned long)(unsigned char)(cp)[0]) | \
28   ((unsigned long)(unsigned char)(cp)[1] << 8))
29
30 #define PUT_16BIT_LSB_FIRST(cp, value) ( \
31   (cp)[0] = (value), \
32   (cp)[1] = (value) >> 8 )
33
34 #define GET_32BIT_MSB_FIRST(cp) \
35   (((unsigned long)(unsigned char)(cp)[0] << 24) | \
36   ((unsigned long)(unsigned char)(cp)[1] << 16) | \
37   ((unsigned long)(unsigned char)(cp)[2] << 8) | \
38   ((unsigned long)(unsigned char)(cp)[3]))
39
40 #define PUT_32BIT_MSB_FIRST(cp, value) ( \
41   (cp)[0] = (value) >> 24, \
42   (cp)[1] = (value) >> 16, \
43   (cp)[2] = (value) >> 8, \
44   (cp)[3] = (value) )
45
46 #define GET_16BIT_MSB_FIRST(cp) \
47   (((unsigned long)(unsigned char)(cp)[0] << 8) | \
48   ((unsigned long)(unsigned char)(cp)[1]))
49
50 #define PUT_16BIT_MSB_FIRST(cp, value) ( \
51   (cp)[0] = (value) >> 8, \
52   (cp)[1] = (value) )
53
54 struct PFwdPrivate {
55     const struct plug_function_table *fn;
56     /* the above variable absolutely *must* be the first in this structure */
57     void *c;                           /* (channel) data used by ssh.c */
58     void *backhandle;                  /* instance of SSH backend itself */
59     /* Note that backhandle need not be filled in if c is non-NULL */
60     Socket s;
61     int throttled, throttle_override;
62     int ready;
63     /*
64      * `dynamic' does double duty. It's set to 0 for an ordinary
65      * forwarded port, and nonzero for SOCKS-style dynamic port
66      * forwarding; but it also represents the state of the SOCKS
67      * exchange.
68      */
69     int dynamic;
70     /*
71      * `hostname' and `port' are the real hostname and port, once
72      * we know what we're connecting to; they're unused for this
73      * purpose while conducting a local SOCKS exchange, which means
74      * we can also use them as a buffer and pointer for reading
75      * data from the SOCKS client.
76      */
77     char hostname[256+8];
78     int port;
79     /*
80      * When doing dynamic port forwarding, we can receive
81      * connection data before we are actually able to send it; so
82      * we may have to temporarily hold some in a dynamically
83      * allocated buffer here.
84      */
85     void *buffer;
86     int buflen;
87 };
88
89 static int pfd_closing(Plug plug, char *error_msg, int error_code,
90                        int calling_back)
91 {
92     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
93
94     /*
95      * We have no way to communicate down the forwarded connection,
96      * so if an error occurred on the socket, we just ignore it
97      * and treat it like a proper close.
98      */
99     if (pr->c)
100         sshfwd_close(pr->c);
101     pfd_close(pr->s);
102     return 1;
103 }
104
105 static int pfd_receive(Plug plug, int urgent, char *data, int len)
106 {
107     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
108     if (pr->dynamic) {
109         while (len--) {
110             if (pr->port >= lenof(pr->hostname)) {
111                 if ((pr->dynamic >> 12) == 4) {
112                     /* Send back a SOCKS 4 error before closing. */
113                     char data[8];
114                     memset(data, 0, sizeof(data));
115                     data[1] = 91;      /* generic `request rejected' */
116                     sk_write(pr->s, data, 8);
117                 }
118                 pfd_close(pr->s);
119                 return 1;
120             }
121             pr->hostname[pr->port++] = *data++;
122
123             /*
124              * Now check what's in the buffer to see if it's a
125              * valid and complete message in the SOCKS exchange.
126              */
127             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&
128                 pr->hostname[0] == 4) {
129                 /*
130                  * SOCKS 4.
131                  */
132                 if (pr->dynamic == 1)
133                     pr->dynamic = 0x4000;
134                 if (pr->port < 2) continue;/* don't have command code yet */
135                 if (pr->hostname[1] != 1) {
136                     /* Send back a SOCKS 4 error before closing. */
137                     char data[8];
138                     memset(data, 0, sizeof(data));
139                     data[1] = 91;      /* generic `request rejected' */
140                     sk_write(pr->s, data, 8);
141                     pfd_close(pr->s);
142                     return 1;
143                 }
144                 if (pr->port < 8) continue;   /* haven't started username */
145                 if (pr->hostname[pr->port-1] != 0)
146                     continue;          /* haven't _finished_ username */
147                 /*
148                  * Now we have a full SOCKS 4 request. Check it to
149                  * see if it's a SOCKS 4A request.
150                  */
151                 if (pr->hostname[4] == 0 && pr->hostname[5] == 0 &&
152                     pr->hostname[6] == 0 && pr->hostname[7] != 0) {
153                     /*
154                      * It's SOCKS 4A. So if we haven't yet
155                      * collected the host name, we should continue
156                      * waiting for data in order to do so; if we
157                      * have, we can go ahead.
158                      */
159                     int len;
160                     if (pr->dynamic == 0x4000) {
161                         pr->dynamic = 0x4001;
162                         pr->port = 8;      /* reset buffer to overwrite name */
163                         continue;
164                     }
165                     pr->hostname[0] = 0;   /* reply version code */
166                     pr->hostname[1] = 90;   /* request granted */
167                     sk_write(pr->s, pr->hostname, 8);
168                     len= pr->port;
169                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);
170                     memmove(pr->hostname, pr->hostname + 8, len);
171                     goto connect;
172                 } else {
173                     /*
174                      * It's SOCKS 4, which means we should format
175                      * the IP address into the hostname string and
176                      * then just go.
177                      */
178                     pr->hostname[0] = 0;   /* reply version code */
179                     pr->hostname[1] = 90;   /* request granted */
180                     sk_write(pr->s, pr->hostname, 8);
181                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);
182                     sprintf(pr->hostname, "%d.%d.%d.%d",
183                             (unsigned char)pr->hostname[4],
184                             (unsigned char)pr->hostname[5],
185                             (unsigned char)pr->hostname[6],
186                             (unsigned char)pr->hostname[7]);
187                     goto connect;
188                 }
189             }
190
191             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&
192                 pr->hostname[0] == 5) {
193                 /*
194                  * SOCKS 5.
195                  */
196                 if (pr->dynamic == 1)
197                     pr->dynamic = 0x5000;
198
199                 if (pr->dynamic == 0x5000) {
200                     int i, method;
201                     char data[2];
202                     /*
203                      * We're receiving a set of method identifiers.
204                      */
205                     if (pr->port < 2) continue;/* no method count yet */
206                     if (pr->port < 2 + (unsigned char)pr->hostname[1])
207                         continue;      /* no methods yet */
208                     method = 0xFF;     /* invalid */
209                     for (i = 0; i < (unsigned char)pr->hostname[1]; i++)
210                         if (pr->hostname[2+i] == 0) {
211                             method = 0;/* no auth */
212                             break;
213                         }
214                     data[0] = 5;
215                     data[1] = method;
216                     sk_write(pr->s, data, 2);
217                     pr->dynamic = 0x5001;
218                     pr->port = 0;      /* re-empty the buffer */
219                     continue;
220                 }
221
222                 if (pr->dynamic == 0x5001) {
223                     int atype, alen;
224                     if (pr->port < 6) continue;
225                     atype = (unsigned char)pr->hostname[3];
226                     if (atype == 1)    /* IPv4 address */
227                         alen = 4;
228                     if (atype == 4)    /* IPv6 address */
229                         alen = 16;
230                     if (atype == 3)    /* domain name has leading length */
231                         alen = 1 + (unsigned char)pr->hostname[4];
232                     if (pr->port < 6 + alen) continue;
233                     if (pr->hostname[1] != 1 || pr->hostname[2] != 0) {
234                         pr->hostname[1] = 1;   /* generic failure */
235                         pr->hostname[2] = 0;   /* reserved */
236                         sk_write(pr->s, pr->hostname, pr->port);
237                         pfd_close(pr->s);
238                         return 1;
239                     }
240                     /*
241                      * Now we have a viable connect request. Switch
242                      * on atype.
243                      */
244                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen);
245                     if (atype == 1) {
246                         pr->hostname[1] = 0;   /* succeeded */
247                         sk_write(pr->s, pr->hostname, alen + 6);
248                         sprintf(pr->hostname, "%d.%d.%d.%d",
249                                 (unsigned char)pr->hostname[4],
250                                 (unsigned char)pr->hostname[5],
251                                 (unsigned char)pr->hostname[6],
252                                 (unsigned char)pr->hostname[7]);
253                         goto connect;
254                     } else if (atype == 3) {
255                         pr->hostname[1] = 0;   /* succeeded */
256                         sk_write(pr->s, pr->hostname, alen + 6);
257                         memmove(pr->hostname, pr->hostname + 5, alen-1);
258                         pr->hostname[alen-1] = '\0';
259                         goto connect;
260                     } else {
261                         /*
262                          * Unknown address type. (FIXME: support IPv6!)
263                          */
264                         pr->hostname[1] = 8;   /* atype not supported */
265                         sk_write(pr->s, pr->hostname, pr->port);
266                         pfd_close(pr->s);
267                         return 1;                       
268                     }
269                 }
270             }
271             
272             /*
273              * If we get here without either having done `continue'
274              * or `goto connect', it must be because there is no
275              * sensible interpretation of what's in our buffer. So
276              * close the connection rudely.
277              */
278             pfd_close(pr->s);
279             return 1;
280         }
281         return 1;
282
283         /*
284          * We come here when we're ready to make an actual
285          * connection.
286          */
287         connect:
288
289         pr->c = new_sock_channel(pr->backhandle, pr->s);
290         if (pr->c == NULL) {
291             pfd_close(pr->s);
292             return 1;
293         } else {
294             /* asks to forward to the specified host/port for this */
295             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
296         }
297         pr->dynamic = 0;
298
299         /*
300          * Now freeze the socket until the SSH server confirms the
301          * connection.
302          */
303         sk_set_frozen(pr->s, 1);
304         /*
305          * If there's any data remaining in our current buffer,
306          * save it to be sent on pfd_confirm().
307          */
308         if (len > 0) {
309             pr->buffer = snewn(len, char);
310             memcpy(pr->buffer, data, len);
311             pr->buflen = len;
312         }
313     }
314     if (pr->ready) {
315         if (sshfwd_write(pr->c, data, len) > 0) {
316             pr->throttled = 1;
317             sk_set_frozen(pr->s, 1);
318         }
319     }
320     return 1;
321 }
322
323 static void pfd_sent(Plug plug, int bufsize)
324 {
325     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
326
327     if (pr->c)
328         sshfwd_unthrottle(pr->c, bufsize);
329 }
330
331 /*
332  * Called when receiving a PORT OPEN from the server
333  */
334 char *pfd_newconnect(Socket *s, char *hostname, int port, void *c,
335                      const Config *cfg)
336 {
337     static const struct plug_function_table fn_table = {
338         pfd_closing,
339         pfd_receive,
340         pfd_sent,
341         NULL
342     };
343
344     SockAddr addr;
345     char *err, *dummy_realhost;
346     struct PFwdPrivate *pr;
347
348     /*
349      * Try to find host.
350      */
351     addr = name_lookup(hostname, port, &dummy_realhost, cfg);
352     if ((err = sk_addr_error(addr)) != NULL)
353         return err;
354
355     /*
356      * Open socket.
357      */
358     pr = snew(struct PFwdPrivate);
359     pr->buffer = NULL;
360     pr->fn = &fn_table;
361     pr->throttled = pr->throttle_override = 0;
362     pr->ready = 1;
363     pr->c = c;
364     pr->backhandle = NULL;             /* we shouldn't need this */
365     pr->dynamic = 0;
366
367     pr->s = *s = new_connection(addr, dummy_realhost, port,
368                                 0, 1, 0, (Plug) pr, cfg);
369     if ((err = sk_socket_error(*s)) != NULL) {
370         sfree(pr);
371         return err;
372     }
373
374     sk_set_private_ptr(*s, pr);
375     sk_addr_free(addr);
376     return NULL;
377 }
378
379 /*
380  called when someone connects to the local port
381  */
382
383 static int pfd_accepting(Plug p, void *sock)
384 {
385     static const struct plug_function_table fn_table = {
386         pfd_closing,
387         pfd_receive,
388         pfd_sent,
389         NULL
390     };
391     struct PFwdPrivate *pr, *org;
392     Socket s;
393     char *err;
394
395     org = (struct PFwdPrivate *)p;
396     pr = snew(struct PFwdPrivate);
397     pr->buffer = NULL;
398     pr->fn = &fn_table;
399
400     pr->c = NULL;
401     pr->backhandle = org->backhandle;
402
403     pr->s = s = sk_register(sock, (Plug) pr);
404     if ((err = sk_socket_error(s)) != NULL) {
405         sfree(pr);
406         return err != NULL;
407     }
408
409     sk_set_private_ptr(s, pr);
410
411     pr->throttled = pr->throttle_override = 0;
412     pr->ready = 0;
413
414     if (org->dynamic) {
415         pr->dynamic = 1;
416         pr->port = 0;                  /* hostname buffer is so far empty */
417         sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */
418     } else {
419         pr->dynamic = 0;
420         strcpy(pr->hostname, org->hostname);
421         pr->port = org->port;   
422         pr->c = new_sock_channel(org->backhandle, s);
423
424         if (pr->c == NULL) {
425             sfree(pr);
426             return 1;
427         } else {
428             /* asks to forward to the specified host/port for this */
429             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
430         }
431     }
432
433     return 0;
434 }
435
436
437 /* Add a new forwarding from port -> desthost:destport
438  sets up a listener on the local machine on (srcaddr:)port
439  */
440 char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port,
441                      void *backhandle, const Config *cfg)
442 {
443     static const struct plug_function_table fn_table = {
444         pfd_closing,
445         pfd_receive,                   /* should not happen... */
446         pfd_sent,                      /* also should not happen */
447         pfd_accepting
448     };
449
450     char *err;
451     struct PFwdPrivate *pr;
452     Socket s;
453
454     /*
455      * Open socket.
456      */
457     pr = snew(struct PFwdPrivate);
458     pr->buffer = NULL;
459     pr->fn = &fn_table;
460     pr->c = NULL;
461     if (desthost) {
462         strcpy(pr->hostname, desthost);
463         pr->port = destport;
464         pr->dynamic = 0;
465     } else
466         pr->dynamic = 1;
467     pr->throttled = pr->throttle_override = 0;
468     pr->ready = 0;
469     pr->backhandle = backhandle;
470
471     pr->s = s = new_listener(srcaddr, port, (Plug) pr,
472                              !cfg->lport_acceptall, cfg);
473     if ((err = sk_socket_error(s)) != NULL) {
474         sfree(pr);
475         return err;
476     }
477
478     sk_set_private_ptr(s, pr);
479
480     return NULL;
481 }
482
483 void pfd_close(Socket s)
484 {
485     struct PFwdPrivate *pr;
486
487     if (!s)
488         return;
489
490     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
491
492     sfree(pr->buffer);
493     sfree(pr);
494
495     sk_close(s);
496 }
497
498 void pfd_unthrottle(Socket s)
499 {
500     struct PFwdPrivate *pr;
501     if (!s)
502         return;
503     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
504
505     pr->throttled = 0;
506     sk_set_frozen(s, pr->throttled || pr->throttle_override);
507 }
508
509 void pfd_override_throttle(Socket s, int enable)
510 {
511     struct PFwdPrivate *pr;
512     if (!s)
513         return;
514     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
515
516     pr->throttle_override = enable;
517     sk_set_frozen(s, pr->throttled || pr->throttle_override);
518 }
519
520 /*
521  * Called to send data down the raw connection.
522  */
523 int pfd_send(Socket s, char *data, int len)
524 {
525     if (s == NULL)
526         return 0;
527     return sk_write(s, data, len);
528 }
529
530
531 void pfd_confirm(Socket s)
532 {
533     struct PFwdPrivate *pr;
534
535     if (s == NULL)
536         return;
537
538     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
539     pr->ready = 1;
540     sk_set_frozen(s, 0);
541     sk_write(s, NULL, 0);
542     if (pr->buffer) {
543         sshfwd_write(pr->c, pr->buffer, pr->buflen);
544         sfree(pr->buffer);
545         pr->buffer = NULL;
546     }
547 }