]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - portfwd.c
Colin's const-fixing Patch Of Death. Seems to build fine on Windows
[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, const 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 = 0;
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 const char *pfd_newconnect(Socket *s, char *hostname, int port,
335                            void *c, 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     const char *err;
346     char *dummy_realhost;
347     struct PFwdPrivate *pr;
348
349     /*
350      * Try to find host.
351      */
352     addr = name_lookup(hostname, port, &dummy_realhost, cfg);
353     if ((err = sk_addr_error(addr)) != NULL)
354         return err;
355
356     /*
357      * Open socket.
358      */
359     pr = snew(struct PFwdPrivate);
360     pr->buffer = NULL;
361     pr->fn = &fn_table;
362     pr->throttled = pr->throttle_override = 0;
363     pr->ready = 1;
364     pr->c = c;
365     pr->backhandle = NULL;             /* we shouldn't need this */
366     pr->dynamic = 0;
367
368     pr->s = *s = new_connection(addr, dummy_realhost, port,
369                                 0, 1, 0, (Plug) pr, cfg);
370     if ((err = sk_socket_error(*s)) != NULL) {
371         sfree(pr);
372         return err;
373     }
374
375     sk_set_private_ptr(*s, pr);
376     sk_addr_free(addr);
377     return NULL;
378 }
379
380 /*
381  called when someone connects to the local port
382  */
383
384 static int pfd_accepting(Plug p, void *sock)
385 {
386     static const struct plug_function_table fn_table = {
387         pfd_closing,
388         pfd_receive,
389         pfd_sent,
390         NULL
391     };
392     struct PFwdPrivate *pr, *org;
393     Socket s;
394     const char *err;
395
396     org = (struct PFwdPrivate *)p;
397     pr = snew(struct PFwdPrivate);
398     pr->buffer = NULL;
399     pr->fn = &fn_table;
400
401     pr->c = NULL;
402     pr->backhandle = org->backhandle;
403
404     pr->s = s = sk_register(sock, (Plug) pr);
405     if ((err = sk_socket_error(s)) != NULL) {
406         sfree(pr);
407         return err != NULL;
408     }
409
410     sk_set_private_ptr(s, pr);
411
412     pr->throttled = pr->throttle_override = 0;
413     pr->ready = 0;
414
415     if (org->dynamic) {
416         pr->dynamic = 1;
417         pr->port = 0;                  /* hostname buffer is so far empty */
418         sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */
419     } else {
420         pr->dynamic = 0;
421         strcpy(pr->hostname, org->hostname);
422         pr->port = org->port;   
423         pr->c = new_sock_channel(org->backhandle, s);
424
425         if (pr->c == NULL) {
426             sfree(pr);
427             return 1;
428         } else {
429             /* asks to forward to the specified host/port for this */
430             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
431         }
432     }
433
434     return 0;
435 }
436
437
438 /* Add a new forwarding from port -> desthost:destport
439  sets up a listener on the local machine on (srcaddr:)port
440  */
441 const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
442                            int port, void *backhandle, const Config *cfg)
443 {
444     static const struct plug_function_table fn_table = {
445         pfd_closing,
446         pfd_receive,                   /* should not happen... */
447         pfd_sent,                      /* also should not happen */
448         pfd_accepting
449     };
450
451     const char *err;
452     struct PFwdPrivate *pr;
453     Socket s;
454
455     /*
456      * Open socket.
457      */
458     pr = snew(struct PFwdPrivate);
459     pr->buffer = NULL;
460     pr->fn = &fn_table;
461     pr->c = NULL;
462     if (desthost) {
463         strcpy(pr->hostname, desthost);
464         pr->port = destport;
465         pr->dynamic = 0;
466     } else
467         pr->dynamic = 1;
468     pr->throttled = pr->throttle_override = 0;
469     pr->ready = 0;
470     pr->backhandle = backhandle;
471
472     pr->s = s = new_listener(srcaddr, port, (Plug) pr,
473                              !cfg->lport_acceptall, cfg);
474     if ((err = sk_socket_error(s)) != NULL) {
475         sfree(pr);
476         return err;
477     }
478
479     sk_set_private_ptr(s, pr);
480
481     return NULL;
482 }
483
484 void pfd_close(Socket s)
485 {
486     struct PFwdPrivate *pr;
487
488     if (!s)
489         return;
490
491     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
492
493     sfree(pr->buffer);
494     sfree(pr);
495
496     sk_close(s);
497 }
498
499 void pfd_unthrottle(Socket s)
500 {
501     struct PFwdPrivate *pr;
502     if (!s)
503         return;
504     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
505
506     pr->throttled = 0;
507     sk_set_frozen(s, pr->throttled || pr->throttle_override);
508 }
509
510 void pfd_override_throttle(Socket s, int enable)
511 {
512     struct PFwdPrivate *pr;
513     if (!s)
514         return;
515     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
516
517     pr->throttle_override = enable;
518     sk_set_frozen(s, pr->throttled || pr->throttle_override);
519 }
520
521 /*
522  * Called to send data down the raw connection.
523  */
524 int pfd_send(Socket s, char *data, int len)
525 {
526     if (s == NULL)
527         return 0;
528     return sk_write(s, data, len);
529 }
530
531
532 void pfd_confirm(Socket s)
533 {
534     struct PFwdPrivate *pr;
535
536     if (s == NULL)
537         return;
538
539     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
540     pr->ready = 1;
541     sk_set_frozen(s, 0);
542     sk_write(s, NULL, 0);
543     if (pr->buffer) {
544         sshfwd_write(pr->c, pr->buffer, pr->buflen);
545         sfree(pr->buffer);
546         pr->buffer = NULL;
547     }
548 }