Open-Source-Software-Entwicklung und Downloads

Browse Subversion Repository

Contents of /trunk/ttssh2/ttxssh/fwd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3227 - (show annotations) (download) (as text)
Tue Mar 24 15:10:33 2009 UTC (15 years, 1 month ago) by maya
File MIME type: text/x-csrc
File size: 64680 byte(s)
CVS から SVN へ移行: 改行コードを LF から CR+LF へ変換
1 /*
2 Copyright (c) 1998-2001, Robert O'Callahan
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer.
10
11 Redistributions in binary form must reproduce the above copyright notice, this list
12 of conditions and the following disclaimer in the documentation and/or other materials
13 provided with the distribution.
14
15 The name of Robert O'Callahan may not be used to endorse or promote products derived from
16 this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 This code is copyright (C) 1998-1999 Robert O'Callahan.
31 See LICENSE.TXT for the license.
32 */
33
34 #include "ttxssh.h"
35
36 #include "x11util.h"
37
38 #include "fwd.h"
39
40 #include <assert.h>
41 #ifndef NO_INET6
42 #include "WSAAsyncGetAddrInfo.h"
43 #endif /* NO_INET6 */
44
45 #define WM_SOCK_ACCEPT (WM_APP+9999)
46 #define WM_SOCK_IO (WM_APP+9998)
47 #define WM_SOCK_GOTNAME (WM_APP+9997)
48
49 #define CHANNEL_READ_BUF_SIZE 8192
50
51 static LRESULT CALLBACK accept_wnd_proc(HWND wnd, UINT msg, WPARAM wParam,
52 LPARAM lParam);
53
54 static int find_request_num(PTInstVar pvar, SOCKET s)
55 {
56 int i;
57 #ifndef NO_INET6
58 int j;
59 #endif /* NO_INET6 */
60
61 if (s == INVALID_SOCKET)
62 return -1;
63
64 #ifndef NO_INET6
65 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
66 for (j = 0; j < pvar->fwd_state.requests[i].num_listening_sockets;
67 ++j) {
68 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0
69 && pvar->fwd_state.requests[i].listening_sockets[j] == s) {
70 return i;
71 }
72 }
73 }
74 #else
75 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
76 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0
77 && pvar->fwd_state.requests[i].listening_socket == s) {
78 return i;
79 }
80 }
81 #endif /* NO_INET6 */
82
83 return -1;
84 }
85
86 static int find_channel_num(PTInstVar pvar, SOCKET s)
87 {
88 int i;
89
90 if (s == INVALID_SOCKET)
91 return -1;
92
93 for (i = 0; i < pvar->fwd_state.num_channels; i++) {
94 if (pvar->fwd_state.channels[i].local_socket == s) {
95 return i;
96 }
97 }
98
99 return -1;
100 }
101
102 static int find_request_num_from_async_request(PTInstVar pvar,
103 HANDLE request)
104 {
105 int i;
106
107 if (request == 0)
108 return -1;
109
110 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
111 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0
112 && pvar->fwd_state.requests[i].to_host_lookup_handle == request) {
113 return i;
114 }
115 }
116
117 return -1;
118 }
119
120 #ifndef NO_INET6
121 static int find_listening_socket_num(PTInstVar pvar, int request_num,
122 SOCKET s)
123 {
124 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
125 int i;
126
127 for (i = 0; i < request->num_listening_sockets; ++i)
128 if (request->listening_sockets[i] == s)
129 return i;
130
131 /* not found */
132 return -1;
133 }
134 #endif /* NO_INET6 */
135
136 static void drain_matching_messages(HWND wnd, UINT msg, WPARAM wParam)
137 {
138 MSG m;
139 MSG FAR *buf;
140 int buf_len;
141 int buf_size;
142 int i;
143
144 /* fast path for case where there are no suitable messages */
145 if (!PeekMessage(&m, wnd, msg, msg, PM_NOREMOVE)) {
146 return;
147 }
148
149 /* suck out all the messages */
150 buf_size = 1;
151 buf_len = 0;
152 buf = (MSG FAR *) malloc(sizeof(MSG) * buf_size);
153
154 while (PeekMessage(&m, wnd, msg, msg, PM_REMOVE)) {
155 if (buf_len == buf_size) {
156 buf_size *= 2;
157 buf = (MSG FAR *) realloc(buf, sizeof(MSG) * buf_size);
158 }
159
160 buf[buf_len] = m;
161 buf_len++;
162 }
163
164 for (i = 0; i < buf_len; i++) {
165 if (buf[i].wParam != wParam) {
166 PostMessage(wnd, msg, buf[i].wParam, buf[i].lParam);
167 }
168 }
169
170 free(buf);
171 }
172
173 /* hideous hack to fix broken Winsock API.
174 After we close a socket further WM_ messages may arrive for it, according to
175 the docs for WSAAsyncSelect. This sucks because we may allocate a new socket
176 before these messages are processed, which may get the same handle value as
177 the old socket, which may mean that we get confused and try to process the old
178 message according to the new request or channel, which could cause chaos and
179 possibly even security problems.
180 "Solution": scan the accept_wnd message queue whenever we close a socket and
181 remove all pending messages for that socket. Possibly this might not even be
182 enough if there is a system thread that is in the process of posting
183 a new message while during execution of the closesocket. I'm hoping
184 that those actions are serialized...
185 */
186 static void safe_closesocket(PTInstVar pvar, SOCKET s)
187 {
188 HWND wnd = pvar->fwd_state.accept_wnd;
189
190 closesocket(s);
191 if (wnd != NULL) {
192 drain_matching_messages(wnd, WM_SOCK_ACCEPT, (WPARAM) s);
193 drain_matching_messages(wnd, WM_SOCK_IO, (WPARAM) s);
194 }
195 }
196
197 static void safe_WSACancelAsyncRequest(PTInstVar pvar, HANDLE request)
198 {
199 HWND wnd = pvar->fwd_state.accept_wnd;
200
201 WSACancelAsyncRequest(request);
202 if (wnd != NULL) {
203 drain_matching_messages(wnd, WM_SOCK_GOTNAME, (WPARAM) request);
204 }
205 }
206
207 int FWD_check_local_channel_num(PTInstVar pvar, int local_num)
208 {
209 if (local_num < 0 || local_num >= pvar->fwd_state.num_channels
210 || pvar->fwd_state.channels[local_num].status == 0) {
211 UTIL_get_lang_msg("MSG_FWD_LOCAL_CHANNEL_ERROR", pvar,
212 "The server attempted to manipulate a forwarding channel that does not exist.\n"
213 "Either the server has a bug or is hostile. You should close this connection.");
214 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
215 return 0;
216 } else {
217 return 1;
218 }
219 }
220
221 static void request_error(PTInstVar pvar, int request_num, int err)
222 {
223 #ifndef NO_INET6
224 SOCKET FAR *s =
225 pvar->fwd_state.requests[request_num].listening_sockets;
226 int i;
227 #else
228 SOCKET s = pvar->fwd_state.requests[request_num].listening_socket;
229 #endif /* NO_INET6 */
230
231 #ifndef NO_INET6
232 for (i = 0;
233 i < pvar->fwd_state.requests[request_num].num_listening_sockets;
234 ++i) {
235 if (s[i] != INVALID_SOCKET) {
236 safe_closesocket(pvar, s[i]);
237 pvar->fwd_state.requests[request_num].listening_sockets[i] =
238 INVALID_SOCKET;
239 }
240 }
241 #else
242 if (s != INVALID_SOCKET) {
243 safe_closesocket(pvar, s);
244 pvar->fwd_state.requests[request_num].listening_socket =
245 INVALID_SOCKET;
246 }
247 #endif /* NO_INET6 */
248
249 UTIL_get_lang_msg("MSG_FWD_REQUEST_ERROR", pvar,
250 "Communications error while listening for a connection to forward.\n"
251 "The listening port will be terminated.");
252 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
253 }
254
255 static void send_local_connection_closure(PTInstVar pvar, int channel_num)
256 {
257 FWDChannel FAR *channel = pvar->fwd_state.channels + channel_num;
258
259 if ((channel->status & (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED))
260 == (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED)) {
261 SSH_channel_input_eof(pvar, channel->remote_num, channel_num);
262 SSH_channel_output_eof(pvar, channel->remote_num);
263 channel->status |= FWD_CLOSED_LOCAL_IN | FWD_CLOSED_LOCAL_OUT;
264 }
265 }
266
267 static void closed_local_connection(PTInstVar pvar, int channel_num)
268 {
269 FWDChannel FAR *channel = pvar->fwd_state.channels + channel_num;
270
271 if (channel->local_socket != INVALID_SOCKET) {
272 safe_closesocket(pvar, channel->local_socket);
273 channel->local_socket = INVALID_SOCKET;
274
275 send_local_connection_closure(pvar, channel_num);
276 }
277 }
278
279 /* This gets called when a request becomes both deleted and has no
280 active channels. */
281 static void really_delete_request(PTInstVar pvar, int request_num)
282 {
283 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
284
285 if (request->to_host_lookup_handle != 0) {
286 safe_WSACancelAsyncRequest(pvar, request->to_host_lookup_handle);
287 request->to_host_lookup_handle = 0;
288 }
289 #ifndef NO_INET6
290 /*****/
291 /* freeaddrinfo(); */
292 #else
293 free(request->to_host_hostent_buf);
294 request->to_host_hostent_buf = NULL;
295 #endif /* NO_INET6 */
296 }
297
298 void FWD_free_channel(PTInstVar pvar, uint32 local_channel_num)
299 {
300 FWDChannel FAR *channel = &pvar->fwd_state.channels[local_channel_num];
301
302 if (channel->type == TYPE_AGENT) {
303 buffer_free(channel->agent_msg);
304 // channel_close ���� TTSSH �I������2���������������A���d free �h�~������
305 channel->agent_msg = NULL;
306 channel->status = 0;
307 }
308 else {
309 UTIL_destroy_sock_write_buf(&channel->writebuf);
310 if (channel->filter != NULL) {
311 channel->filter(channel->filter_closure, 0, NULL, NULL);
312 channel->filter = NULL;
313 channel->filter_closure = NULL;
314 }
315 channel->status = 0;
316 if (channel->local_socket != INVALID_SOCKET) {
317 safe_closesocket(pvar, channel->local_socket);
318 channel->local_socket = INVALID_SOCKET;
319 }
320 }
321
322 if (channel->request_num >= 0) {
323 FWDRequest FAR *request =
324 &pvar->fwd_state.requests[channel->request_num];
325
326 request->num_channels--;
327 if (request->num_channels == 0
328 && (request->status & FWD_DELETED) != 0) {
329 really_delete_request(pvar, channel->request_num);
330 }
331 channel->request_num = -1;
332 }
333 }
334
335 void FWD_channel_input_eof(PTInstVar pvar, uint32 local_channel_num)
336 {
337 FWDChannel FAR *channel;
338
339 if (!FWD_check_local_channel_num(pvar, local_channel_num))
340 return;
341
342 channel = pvar->fwd_state.channels + local_channel_num;
343
344 if (channel->local_socket != INVALID_SOCKET) {
345 shutdown(channel->local_socket, 1);
346 }
347 channel->status |= FWD_CLOSED_REMOTE_IN;
348 if ((channel->status & FWD_CLOSED_REMOTE_OUT) == FWD_CLOSED_REMOTE_OUT) {
349 closed_local_connection(pvar, local_channel_num);
350 FWD_free_channel(pvar, local_channel_num);
351 }
352 }
353
354 void FWD_channel_output_eof(PTInstVar pvar, uint32 local_channel_num)
355 {
356 FWDChannel FAR *channel;
357
358 if (!FWD_check_local_channel_num(pvar, local_channel_num))
359 return;
360
361 channel = pvar->fwd_state.channels + local_channel_num;
362
363 if (channel->local_socket != INVALID_SOCKET) {
364 shutdown(channel->local_socket, 0);
365 }
366 channel->status |= FWD_CLOSED_REMOTE_OUT;
367 if ((channel->status & FWD_CLOSED_REMOTE_IN) == FWD_CLOSED_REMOTE_IN) {
368 closed_local_connection(pvar, local_channel_num);
369 FWD_free_channel(pvar, local_channel_num);
370 }
371 }
372
373 static char FAR *describe_socket_error(PTInstVar pvar, int code)
374 {
375 switch (code) {
376 case WSAECONNREFUSED:
377 UTIL_get_lang_msg("MSG_FWD_REFUSED_ERROR", pvar,
378 "Connection refused (perhaps the service is not currently running)");
379 return pvar->ts->UIMsg;
380 case WSAENETDOWN:
381 case WSAENETUNREACH:
382 case WSAEHOSTUNREACH:
383 UTIL_get_lang_msg("MSG_FWD_NETDOWN_ERROR", pvar,
384 "The machine could not be contacted (possibly a network problem)");
385 return pvar->ts->UIMsg;
386 case WSAETIMEDOUT:
387 case WSAEHOSTDOWN:
388 UTIL_get_lang_msg("MSG_FWD_MACHINEDOWN_ERROR", pvar,
389 "The machine could not be contacted (possibly the machine is down)");
390 return pvar->ts->UIMsg;
391 case WSATRY_AGAIN:
392 case WSANO_RECOVERY:
393 case WSANO_ADDRESS:
394 case WSAHOST_NOT_FOUND:
395 UTIL_get_lang_msg("MSG_FWD_ADDRNOTFOUTD_ERROR", pvar,
396 "No address was found for the machine");
397 return pvar->ts->UIMsg;
398 default:
399 UTIL_get_lang_msg("MSG_FWD_CONNECT_ERROR", pvar,
400 "The forwarding connection could not be established");
401 return pvar->ts->UIMsg;
402 }
403 }
404
405 static void channel_error(PTInstVar pvar, char FAR * action,
406 int channel_num, int err)
407 {
408 char FAR *err_msg;
409 char uimsg[MAX_UIMSG];
410
411 closed_local_connection(pvar, channel_num);
412
413 switch (err) {
414 case WSAECONNRESET:
415 case WSAECONNABORTED:
416 err_msg = NULL;
417 break;
418 default:
419 strncpy_s(uimsg, sizeof(uimsg), describe_socket_error(pvar, err), _TRUNCATE);
420 err_msg = uimsg;
421 }
422
423 if (err_msg != NULL) {
424 char buf[1024];
425
426 UTIL_get_lang_msg("MSG_FWD_CHANNEL_ERROR", pvar,
427 "Communications error %s forwarded local %s.\n"
428 "%s (code %d).\n"
429 "The forwarded connection will be closed.");
430 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
431 pvar->ts->UIMsg, action,
432 pvar->fwd_state.requests[pvar->fwd_state.channels[channel_num].
433 request_num].spec.from_port_name,
434 err_msg, err);
435 notify_nonfatal_error(pvar, buf);
436 }
437 }
438
439 static void channel_opening_error(PTInstVar pvar, int channel_num, int err)
440 {
441 char buf[1024];
442 FWDChannel FAR *channel = &pvar->fwd_state.channels[channel_num];
443 FWDRequest FAR *request =
444 &pvar->fwd_state.requests[channel->request_num];
445 char uimsg[MAX_UIMSG];
446
447 SSH_fail_channel_open(pvar, channel->remote_num);
448 strncpy_s(uimsg, sizeof(uimsg), describe_socket_error(pvar, err), _TRUNCATE);
449 if (request->spec.type == FWD_REMOTE_X11_TO_LOCAL) {
450 UTIL_get_lang_msg("MSG_FWD_CHANNEL_OPEN_X_ERROR", pvar,
451 "The server attempted to forward a connection through this machine.\n"
452 "It requested a connection to the X server on %s (screen %d).\n"
453 "%s.\n" "The forwarded connection will be closed.");
454 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
455 pvar->ts->UIMsg,
456 request->spec.to_host, request->spec.to_port - 6000,
457 uimsg);
458 } else {
459 UTIL_get_lang_msg("MSG_FWD_CHANNEL_OPEN_ERROR", pvar,
460 "The server attempted to forward a connection through this machine.\n"
461 "It requested a connection to %s (port %s).\n" "%s.\n"
462 "The forwarded connection will be closed.");
463 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
464 pvar->ts->UIMsg,
465 request->spec.to_host, request->spec.to_port_name,
466 uimsg);
467 }
468 notify_nonfatal_error(pvar, buf);
469 FWD_free_channel(pvar, channel_num);
470 }
471
472 static void init_local_IP_numbers(PTInstVar pvar)
473 {
474 #ifndef NO_INET6
475 struct addrinfo hints;
476 struct addrinfo FAR *res0;
477 struct addrinfo FAR *res;
478 char buf[1024];
479 int num_addrs = 0;
480 int i;
481 struct sockaddr_storage FAR *addrs;
482
483 if (!gethostname(buf, sizeof(buf))) {
484 memset(&hints, 0, sizeof(hints));
485 if (getaddrinfo(buf, NULL, &hints, &res0))
486 res0 = NULL;
487
488 /* count number of addresses */
489 for (res = res0; res; res = res->ai_next)
490 num_addrs++;
491 }
492
493 addrs =
494 (struct sockaddr_storage FAR *)
495 malloc(sizeof(struct sockaddr_storage) * (num_addrs + 1));
496 for (res = res0, i = 0; i < num_addrs; ++i, res = res->ai_next)
497 memcpy(&addrs[i], res->ai_addr, res->ai_addrlen);
498
499 pvar->fwd_state.local_host_IP_numbers = addrs;
500
501 /* terminated by all zero filled sockaddr_storage */
502 memset(&addrs[num_addrs], 0, sizeof(struct sockaddr_storage));
503 #else
504 HOSTENT FAR *hostent;
505 char buf[1024];
506 int num_addrs = 0;
507 uint32 FAR *addrs;
508
509 if (!gethostname(buf, sizeof(buf))) {
510 hostent = gethostbyname(buf);
511
512 if (hostent != NULL) {
513 for (; hostent->h_addr_list[num_addrs] != NULL; num_addrs++) {
514 }
515 }
516 } else {
517 hostent = NULL;
518 }
519
520 addrs = (uint32 FAR *) malloc(sizeof(uint32) * (num_addrs + 1));
521 pvar->fwd_state.local_host_IP_numbers = addrs;
522 if (hostent != NULL) {
523 int i;
524
525 for (i = 0; i < num_addrs; i++) {
526 addrs[i] = ntohl(*(uint32 FAR *) hostent->h_addr_list[i]);
527 }
528 }
529 addrs[num_addrs] = 0;
530 #endif /* NO_INET6 */
531 }
532
533 #ifndef NO_INET6
534 static BOOL validate_IP_number(PTInstVar pvar, struct sockaddr FAR * addr)
535 {
536 #else
537 static BOOL validate_IP_number(PTInstVar pvar, uint32 addr)
538 {
539 #endif /* NO_INET6 */
540 #ifndef NO_INET6
541 int i;
542 struct sockaddr_storage zss; /* all bytes are filled by zero */
543
544 /* Should we allow a wider range of loopback addresses here?
545 i.e. 127.xx.xx.xx or ::1
546 Wouldn't want to introduce a security hole if there's
547 some OS bug that lets an intruder get packets from us
548 to such an address */
549 switch (addr->sa_family) {
550 case AF_INET:
551 if (((struct sockaddr_in FAR *) addr)->sin_addr.s_addr ==
552 htonl(INADDR_LOOPBACK))
553 return TRUE;
554 break;
555 case AF_INET6:
556 if (IN6_IS_ADDR_LOOPBACK
557 (&(((struct sockaddr_in6 FAR *) addr)->sin6_addr)))
558 return TRUE;
559 break;
560 default:
561 /* NOT REACHED */
562 break;
563 }
564
565 if (pvar->fwd_state.local_host_IP_numbers == NULL) {
566 init_local_IP_numbers(pvar);
567 }
568
569 memset(&zss, 0, sizeof(zss));
570 for (i = 0;; i++) {
571 if (memcmp
572 (&pvar->fwd_state.local_host_IP_numbers[i], &zss,
573 sizeof(struct sockaddr_storage)) == 0)
574 break;
575
576 switch (addr->sa_family) {
577 case AF_INET:
578 if (memcmp
579 (&pvar->fwd_state.local_host_IP_numbers[i], addr,
580 sizeof(struct sockaddr_in)) == 0)
581 return TRUE;
582 break;
583 case AF_INET6:
584 if (memcmp
585 (&pvar->fwd_state.local_host_IP_numbers[i], addr,
586 sizeof(struct sockaddr_in6)) == 0)
587 return TRUE;
588 break;
589 default:
590 /* NOT REACHED */
591 break;
592 }
593 }
594 return FALSE;
595 #else
596 int i;
597
598 if (pvar->settings.LocalForwardingIdentityCheck) {
599 /* Should we allow a wider range of loopback addresses here?
600 i.e. 127.xx.xx.xx
601 Wouldn't want to introduce a security hole if there's
602 some OS bug that lets an intruder get packets from us
603 to such an address */
604 if (addr == INADDR_LOOPBACK) {
605 return TRUE;
606 }
607
608 if (pvar->fwd_state.local_host_IP_numbers == NULL) {
609 init_local_IP_numbers(pvar);
610 }
611
612 for (i = 0; pvar->fwd_state.local_host_IP_numbers[i] != 0; i++) {
613 if (pvar->fwd_state.local_host_IP_numbers[i] == addr) {
614 return TRUE;
615 }
616 }
617
618 return FALSE;
619 } else {
620 return TRUE;
621 }
622 #endif /* NO_INET6 */
623 }
624
625 static int alloc_channel(PTInstVar pvar, int new_status,
626 int new_request_num)
627 {
628 int i;
629 int new_num_channels;
630 int new_channel = -1;
631 FWDChannel FAR *channel;
632
633 for (i = 0; i < pvar->fwd_state.num_channels && new_channel < 0; i++) {
634 if (pvar->fwd_state.channels[i].status == 0) {
635 new_channel = i;
636 }
637 }
638
639 if (new_channel < 0) {
640 new_num_channels = pvar->fwd_state.num_channels + 1;
641 pvar->fwd_state.channels =
642 (FWDChannel FAR *) realloc(pvar->fwd_state.channels,
643 sizeof(FWDChannel) *
644 new_num_channels);
645
646 for (; i < new_num_channels; i++) {
647 channel = pvar->fwd_state.channels + i;
648
649 channel->status = 0;
650 channel->local_socket = INVALID_SOCKET;
651 channel->request_num = -1;
652 channel->filter = NULL;
653 channel->filter_closure = NULL;
654 UTIL_init_sock_write_buf(&channel->writebuf);
655 }
656
657 new_channel = pvar->fwd_state.num_channels;
658 pvar->fwd_state.num_channels = new_num_channels;
659 }
660
661 channel = pvar->fwd_state.channels + new_channel;
662
663 channel->status = new_status;
664 channel->request_num = new_request_num;
665 pvar->fwd_state.requests[new_request_num].num_channels++;
666 UTIL_init_sock_write_buf(&channel->writebuf);
667
668 return new_channel;
669 }
670
671 static int alloc_agent_channel(PTInstVar pvar, int remote_channel_num)
672 {
673 int i;
674 int new_num_channels;
675 int new_channel = -1;
676 FWDChannel FAR *channel;
677
678 for (i = 0; i < pvar->fwd_state.num_channels && new_channel < 0; i++) {
679 if (pvar->fwd_state.channels[i].status == 0) {
680 new_channel = i;
681 }
682 }
683
684 if (new_channel < 0) {
685 new_num_channels = pvar->fwd_state.num_channels + 1;
686 pvar->fwd_state.channels =
687 (FWDChannel FAR *) realloc(pvar->fwd_state.channels,
688 sizeof(FWDChannel) *
689 new_num_channels);
690
691 new_channel = pvar->fwd_state.num_channels;
692 pvar->fwd_state.num_channels = new_num_channels;
693 }
694
695 channel = pvar->fwd_state.channels + new_channel;
696 channel->status = FWD_AGENT_DUMMY;
697 channel->remote_num = remote_channel_num;
698 channel->request_num = -1;
699 channel->type = TYPE_AGENT;
700 channel->agent_msg = buffer_init();
701 channel->agent_request_len = 0;
702
703 return new_channel;
704 }
705
706 static HWND make_accept_wnd(PTInstVar pvar)
707 {
708 if (pvar->fwd_state.accept_wnd == NULL) {
709 UTIL_get_lang_msg("DLG_FWDMON_TITLE", pvar, "TTSSH Port Forwarding Monitor");
710 pvar->fwd_state.accept_wnd =
711 CreateWindow("STATIC", pvar->ts->UIMsg,
712 WS_DISABLED | WS_POPUP, 0, 0, 1, 1, NULL, NULL,
713 hInst, NULL);
714 if (pvar->fwd_state.accept_wnd != NULL) {
715 pvar->fwd_state.old_accept_wnd_proc =
716 (WNDPROC) SetWindowLong(pvar->fwd_state.accept_wnd,
717 GWL_WNDPROC,
718 (LONG) accept_wnd_proc);
719 SetWindowLong(pvar->fwd_state.accept_wnd, GWL_USERDATA,
720 (LONG) pvar);
721 }
722 }
723
724 return pvar->fwd_state.accept_wnd;
725 }
726
727 static void connected_local_connection(PTInstVar pvar, int channel_num)
728 {
729 SSH_confirm_channel_open(pvar,
730 pvar->fwd_state.channels[channel_num].
731 remote_num, channel_num);
732 pvar->fwd_state.channels[channel_num].status |= FWD_LOCAL_CONNECTED;
733 }
734
735 static void make_local_connection(PTInstVar pvar, int channel_num)
736 {
737 FWDChannel FAR *channel = pvar->fwd_state.channels + channel_num;
738 FWDRequest FAR *request =
739 pvar->fwd_state.requests + channel->request_num;
740 #ifndef NO_INET6
741 for (channel->to_host_addrs = request->to_host_addrs;
742 channel->to_host_addrs;
743 channel->to_host_addrs = channel->to_host_addrs->ai_next) {
744 channel->local_socket = socket(channel->to_host_addrs->ai_family,
745 channel->to_host_addrs->ai_socktype,
746 channel->to_host_addrs->ai_protocol);
747 if (channel->local_socket == INVALID_SOCKET)
748 continue;
749 if (WSAAsyncSelect
750 (channel->local_socket, make_accept_wnd(pvar), WM_SOCK_IO,
751 FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE) == SOCKET_ERROR) {
752 closesocket(channel->local_socket);
753 channel->local_socket = INVALID_SOCKET;
754 continue;
755 }
756 if (connect(channel->local_socket,
757 channel->to_host_addrs->ai_addr,
758 channel->to_host_addrs->ai_addrlen) != SOCKET_ERROR) {
759 connected_local_connection(pvar, channel_num);
760 return;
761 } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
762 /* do nothing, we'll just wait */
763 return;
764 } else {
765 /* connect() failed */
766 closesocket(channel->local_socket);
767 channel->local_socket = INVALID_SOCKET;
768 continue;
769 }
770 }
771
772 channel_opening_error(pvar, channel_num, WSAGetLastError());
773 #else
774 struct sockaddr_in addr;
775
776 addr.sin_family = AF_INET;
777 addr.sin_port = htons((unsigned short) request->spec.to_port);
778 addr.sin_addr.s_addr = htonl(request->to_host_addr);
779
780 if ((channel->local_socket =
781 socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET
782 && WSAAsyncSelect(channel->local_socket, make_accept_wnd(pvar),
783 WM_SOCK_IO,
784 FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE) !=
785 SOCKET_ERROR) {
786 if (connect
787 (channel->local_socket, (struct sockaddr FAR *) &addr,
788 sizeof(addr)) != SOCKET_ERROR) {
789 connected_local_connection(pvar, channel_num);
790 return;
791 } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
792 /* do nothing, we'll just wait */
793 return;
794 }
795 }
796
797 channel_opening_error(pvar, channel_num, WSAGetLastError());
798 #endif /* NO_INET6 */
799 }
800
801 #ifndef NO_INET6
802 static void accept_local_connection(PTInstVar pvar, int request_num,
803 int listening_socket_num)
804 {
805 #else
806 static void accept_local_connection(PTInstVar pvar, int request_num)
807 {
808 #endif /* NO_INET6 */
809 int channel_num;
810 SOCKET s;
811 #ifndef NO_INET6
812 struct sockaddr_storage addr;
813 char hname[NI_MAXHOST];
814 char strport[NI_MAXSERV]; // ws2tcpip.h
815 #else
816 struct sockaddr addr;
817 #endif /* NO_INET6 */
818 int addrlen = sizeof(addr);
819 char buf[1024];
820 #ifndef INET6
821 BYTE FAR *IP;
822 #endif /* NO_INET6 */
823 FWDChannel FAR *channel;
824 FWDRequest FAR *request = &pvar->fwd_state.requests[request_num];
825 BOOL is_localhost = FALSE;
826
827 #ifndef NO_INET6
828 s = accept(request->listening_sockets[listening_socket_num],
829 (struct sockaddr FAR *) &addr, &addrlen);
830 #else
831 s = accept(request->listening_socket, &addr, &addrlen);
832 #endif /* NO_INET6 */
833 if (s == INVALID_SOCKET)
834 return;
835
836 #ifndef INET6
837 IP = (BYTE FAR *) & ((struct sockaddr_in *) (&addr))->sin_addr.s_addr;
838 #endif
839
840 #ifndef NO_INET6
841 is_localhost = validate_IP_number(pvar, (struct sockaddr FAR *) &addr);
842 if ((pvar->settings.LocalForwardingIdentityCheck && !is_localhost) ||
843 (request->spec.check_identity && !is_localhost)) {
844 char hname[NI_MAXHOST];
845 if (getnameinfo((struct sockaddr FAR *) &addr, addrlen,
846 hname, sizeof(hname), NULL, 0, NI_NUMERICHOST)) {
847 /* NOT REACHED */
848 }
849 UTIL_get_lang_msg("MSG_FWD_HOSTILE_ATTACK_ERROR", pvar,
850 "Host with IP number %s tried to connect to "
851 "forwarded local port %d.\n"
852 "This could be some kind of hostile attack.");
853 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
854 pvar->ts->UIMsg, hname,
855 request->spec.from_port);
856 notify_nonfatal_error(pvar, buf);
857 safe_closesocket(pvar, s);
858 return;
859 }
860 #else
861 if (!validate_IP_number
862 (pvar,
863 ntohl(((struct sockaddr_in *) (&addr))->sin_addr.S_un.S_addr))) {
864 _snprintf(buf, sizeof(buf),
865 "Host with IP number %d.%d.%d.%d tried to connect to "
866 "forwarded local port %d.\n"
867 "This could be some kind of hostile attack.", IP[0],
868 IP[1], IP[2], IP[3], request->spec.from_port);
869 buf[NUM_ELEM(buf) - 1] = 0;
870 notify_nonfatal_error(pvar, buf);
871 safe_closesocket(pvar, s);
872 return;
873 }
874 #endif /* NO_INET6 */
875
876 #ifndef NO_INET6
877 // SSH2 port-forwarding���������������[�g�|�[�g���K�v�B(2005.2.27 yutaka)
878 if (getnameinfo
879 ((struct sockaddr FAR *) &addr, addrlen, hname, sizeof(hname),
880 strport, sizeof(strport), NI_NUMERICHOST | NI_NUMERICSERV)) {
881 /* NOT REACHED */
882 }
883 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
884 "Host %s connecting to port %d; forwarding to %s:%d",
885 hname, request->spec.from_port, request->spec.to_host,
886 request->spec.to_port);
887 #else
888 _snprintf(buf, sizeof(buf),
889 "Host %d.%d.%d.%d connecting to port %d; forwarding to %s:%d",
890 IP[0], IP[1], IP[2], IP[3], request->spec.from_port,
891 request->spec.to_host, request->spec.to_port);
892 buf[NUM_ELEM(buf) - 1] = 0;
893 #endif /* NO_INET6 */
894 notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
895
896 #ifndef NO_INET6
897 strncpy_s(buf, sizeof(buf), hname, _TRUNCATE);
898 #else
899 _snprintf(buf, sizeof(buf), "%d.%d.%d.%d", IP[0], IP[1], IP[2], IP[3]);
900 buf[NUM_ELEM(buf) - 1] = 0;
901 #endif
902
903 channel_num = alloc_channel(pvar, FWD_LOCAL_CONNECTED, request_num);
904 channel = pvar->fwd_state.channels + channel_num;
905
906 channel->local_socket = s;
907 channel->filter_closure = NULL;
908 channel->filter = NULL;
909
910 // add originator-port (2005.2.27 yutaka)
911 SSH_open_channel(pvar, channel_num, request->spec.to_host,
912 request->spec.to_port, buf, atoi(strport));
913 }
914
915 static void write_local_connection_buffer(PTInstVar pvar, int channel_num)
916 {
917 FWDChannel FAR *channel = pvar->fwd_state.channels + channel_num;
918
919 if ((channel->status & (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED))
920 == (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED)) {
921 if (!UTIL_sock_write_more
922 (pvar, &channel->writebuf, channel->local_socket)) {
923 channel_error(pvar, "writing", channel_num, WSAGetLastError());
924 }
925 }
926 }
927
928 static void read_local_connection(PTInstVar pvar, int channel_num)
929 {
930 FWDChannel FAR *channel = pvar->fwd_state.channels + channel_num;
931
932 if ((channel->status & (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED))
933 != (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED)) {
934 return;
935 }
936
937 while (channel->local_socket != INVALID_SOCKET) {
938 char buf[CHANNEL_READ_BUF_SIZE];
939 int amount = recv(channel->local_socket, buf, sizeof(buf), 0);
940 int err;
941
942 if (amount > 0) {
943 char FAR *new_buf = buf;
944 int action = FWD_FILTER_RETAIN;
945
946 if (channel->filter != NULL) {
947 action =
948 channel->filter(channel->filter_closure,
949 FWD_FILTER_FROM_CLIENT, &amount,
950 &new_buf);
951 }
952
953 if (amount > 0
954 && (channel->status & FWD_CLOSED_REMOTE_OUT) == 0) {
955 // �|�[�g�t�H���[�f�B���O���������N���C�A���g���������M�v�����ASSH���M���������T�[�o���������������B
956 SSH_channel_send(pvar, channel_num, channel->remote_num, new_buf,
957 amount);
958 }
959
960 switch (action) {
961 case FWD_FILTER_REMOVE:
962 channel->filter(channel->filter_closure, 0, NULL, NULL);
963 channel->filter = NULL;
964 channel->filter_closure = NULL;
965 break;
966 case FWD_FILTER_CLOSECHANNEL:
967 closed_local_connection(pvar, channel_num);
968 break;
969 }
970 } else if (amount == 0
971 || (err = WSAGetLastError()) == WSAEWOULDBLOCK) {
972 return;
973 } else {
974 channel_error(pvar, "reading", channel_num, err);
975 return;
976 }
977 }
978 }
979
980 static void failed_to_host_addr(PTInstVar pvar, int request_num, int err)
981 {
982 int i;
983
984 for (i = 0; i < pvar->fwd_state.num_channels; i++) {
985 if (pvar->fwd_state.channels[i].request_num == request_num) {
986 channel_opening_error(pvar, i, err);
987 }
988 }
989 }
990
991 static void found_to_host_addr(PTInstVar pvar, int request_num)
992 {
993 int i;
994
995 #ifdef NO_INET6
996 pvar->fwd_state.requests[request_num].to_host_addr =
997 ntohl(*(uint32 FAR *)
998 ((HOSTENT FAR *) pvar->fwd_state.requests[request_num].
999 to_host_hostent_buf)->h_addr_list[0]);
1000 #endif /* NO_INET6 */
1001
1002 for (i = 0; i < pvar->fwd_state.num_channels; i++) {
1003 if (pvar->fwd_state.channels[i].request_num == request_num) {
1004 make_local_connection(pvar, i);
1005 }
1006 }
1007 }
1008
1009 static LRESULT CALLBACK accept_wnd_proc(HWND wnd, UINT msg, WPARAM wParam,
1010 LPARAM lParam)
1011 {
1012 PTInstVar pvar = (PTInstVar) GetWindowLong(wnd, GWL_USERDATA);
1013
1014 if (msg == WM_SOCK_ACCEPT &&
1015 (LOWORD(lParam) == FD_READ || LOWORD(lParam) == FD_CLOSE ||
1016 LOWORD(lParam) == FD_WRITE)) {
1017 msg = WM_SOCK_IO;
1018 }
1019
1020 switch (msg) {
1021 case WM_SOCK_ACCEPT:{
1022 int request_num = find_request_num(pvar, (SOCKET) wParam);
1023
1024 if (request_num < 0)
1025 return TRUE;
1026
1027 if (HIWORD(lParam) != 0) {
1028 request_error(pvar, request_num, HIWORD(lParam));
1029 } else {
1030 #ifndef NO_INET6
1031 int listening_socket_num;
1032 #endif /* NO_INET6 */
1033 switch (LOWORD(lParam)) {
1034 case FD_ACCEPT:
1035 #ifndef NO_INET6
1036 listening_socket_num =
1037 find_listening_socket_num(pvar, request_num,
1038 (SOCKET) wParam);
1039 if (listening_socket_num == -1)
1040 return FALSE;
1041 accept_local_connection(pvar, request_num,
1042 listening_socket_num);
1043 #else
1044 accept_local_connection(pvar, request_num);
1045 #endif /* NO_INET6 */
1046 break;
1047 }
1048 }
1049 return TRUE;
1050 }
1051
1052 case WM_SOCK_GOTNAME:{
1053 int request_num =
1054 find_request_num_from_async_request(pvar, (HANDLE) wParam);
1055
1056 if (request_num < 0)
1057 return TRUE;
1058
1059 if (HIWORD(lParam) != 0) {
1060 failed_to_host_addr(pvar, request_num, HIWORD(lParam));
1061 } else {
1062 found_to_host_addr(pvar, request_num);
1063 }
1064 pvar->fwd_state.requests[request_num].to_host_lookup_handle = 0;
1065 #ifdef NO_INET6
1066 free(pvar->fwd_state.requests[request_num].
1067 to_host_hostent_buf);
1068 pvar->fwd_state.requests[request_num].to_host_hostent_buf =
1069 NULL;
1070 #endif /* NO_INET6 */
1071 return TRUE;
1072 }
1073
1074 case WM_SOCK_IO:{
1075 int channel_num = find_channel_num(pvar, (SOCKET) wParam);
1076 #ifndef NO_INET6
1077 FWDChannel FAR *channel =
1078 pvar->fwd_state.channels + channel_num;
1079 #endif /* NO_INET6 */
1080
1081 if (channel_num < 0)
1082 return TRUE;
1083
1084 if (HIWORD(lParam) != 0) {
1085 #ifndef NO_INET6
1086 if (LOWORD(lParam) == FD_CONNECT) {
1087 if (channel->to_host_addrs->ai_next == NULL) {
1088 /* all protocols were failed */
1089 channel_opening_error(pvar, channel_num,
1090 HIWORD(lParam));
1091 } else {
1092 for (channel->to_host_addrs =
1093 channel->to_host_addrs->ai_next;
1094 channel->to_host_addrs;
1095 channel->to_host_addrs =
1096 channel->to_host_addrs->ai_next) {
1097 channel->local_socket =
1098 socket(channel->to_host_addrs->ai_family,
1099 channel->to_host_addrs->ai_socktype,
1100 channel->to_host_addrs->ai_protocol);
1101 if (channel->local_socket == INVALID_SOCKET)
1102 continue;
1103 if (WSAAsyncSelect
1104 (channel->local_socket,
1105 make_accept_wnd(pvar), WM_SOCK_IO,
1106 FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE
1107 ) == SOCKET_ERROR) {
1108 closesocket(channel->local_socket);
1109 channel->local_socket = INVALID_SOCKET;
1110 continue;
1111 }
1112 if (connect(channel->local_socket,
1113 channel->to_host_addrs->ai_addr,
1114 channel->to_host_addrs->ai_addrlen
1115 ) != SOCKET_ERROR) {
1116 connected_local_connection(pvar,
1117 channel_num);
1118 return TRUE;
1119 } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
1120 /* do nothing, we'll just wait */
1121 return TRUE;
1122 } else {
1123 closesocket(channel->local_socket);
1124 channel->local_socket = INVALID_SOCKET;
1125 continue;
1126 }
1127 }
1128 channel_opening_error(pvar, channel_num,
1129 HIWORD(lParam));
1130 return TRUE;
1131 }
1132 } else {
1133 channel_error(pvar, "accessing", channel_num,
1134 HIWORD(lParam));
1135 return TRUE;
1136 }
1137 #else
1138 if (LOWORD(lParam) == FD_CONNECT) {
1139 channel_opening_error(pvar, channel_num,
1140 HIWORD(lParam));
1141 } else {
1142 channel_error(pvar, "accessing", channel_num,
1143 HIWORD(lParam));
1144 }
1145 #endif /* NO_INET6 */
1146 } else {
1147 switch (LOWORD(lParam)) {
1148 case FD_CONNECT:
1149 connected_local_connection(pvar, channel_num);
1150 break;
1151 case FD_READ:
1152 read_local_connection(pvar, channel_num);
1153 break;
1154 case FD_CLOSE:
1155 read_local_connection(pvar, channel_num);
1156 closed_local_connection(pvar, channel_num);
1157 break;
1158 case FD_WRITE:
1159 write_local_connection_buffer(pvar, channel_num);
1160 break;
1161 }
1162 }
1163 return TRUE;
1164 }
1165 }
1166
1167 return CallWindowProc(pvar->fwd_state.old_accept_wnd_proc, wnd, msg,
1168 wParam, lParam);
1169 }
1170
1171 int FWD_compare_specs(void const FAR * void_spec1,
1172 void const FAR * void_spec2)
1173 {
1174 FWDRequestSpec FAR *spec1 = (FWDRequestSpec FAR *) void_spec1;
1175 FWDRequestSpec FAR *spec2 = (FWDRequestSpec FAR *) void_spec2;
1176 int delta = spec1->from_port - spec2->from_port;
1177
1178 if (delta == 0) {
1179 delta = spec1->type - spec2->type;
1180 }
1181
1182 return delta;
1183 }
1184
1185 /* Check if the server can listen for 'spec' using the old listening spec 'listener'.
1186 We check that the to_port and (for non-X connections) the to_host are equal
1187 so that we never lie to the server about where its forwarded connection is
1188 ending up. Maybe some SSH implementation depends on this information being
1189 reliable, for security? */
1190 static BOOL can_server_listen_using(FWDRequestSpec FAR * listener,
1191 FWDRequestSpec FAR * spec)
1192 {
1193 return listener->type == spec->type
1194 && listener->from_port == spec->from_port
1195 && listener->to_port == spec->to_port
1196 && (spec->type == FWD_REMOTE_X11_TO_LOCAL
1197 || strcmp(listener->to_host, spec->to_host) == 0);
1198 }
1199
1200 BOOL FWD_can_server_listen_for(PTInstVar pvar, FWDRequestSpec FAR * spec)
1201 {
1202 int num_server_listening_requests =
1203 pvar->fwd_state.num_server_listening_specs;
1204
1205 if (num_server_listening_requests < 0) {
1206 return TRUE;
1207 } else {
1208 FWDRequestSpec FAR *listener =
1209 bsearch(spec, pvar->fwd_state.server_listening_specs,
1210 num_server_listening_requests,
1211 sizeof(FWDRequestSpec), FWD_compare_specs);
1212
1213 if (listener == NULL) {
1214 return FALSE;
1215 } else {
1216 return can_server_listen_using(listener, spec);
1217 }
1218 }
1219 }
1220
1221 int FWD_get_num_request_specs(PTInstVar pvar)
1222 {
1223 int num_request_specs = 0;
1224 int i;
1225
1226 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1227 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0) {
1228 num_request_specs++;
1229 }
1230 }
1231
1232 return num_request_specs;
1233 }
1234
1235 void FWD_get_request_specs(PTInstVar pvar, FWDRequestSpec FAR * specs,
1236 int num_specs)
1237 {
1238 int i;
1239
1240 for (i = 0; i < pvar->fwd_state.num_requests && num_specs > 0; i++) {
1241 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0) {
1242 *specs = pvar->fwd_state.requests[i].spec;
1243 num_specs--;
1244 specs++;
1245 }
1246 }
1247 }
1248
1249 /* This function can be called while channels remain open on the request.
1250 Take care.
1251 It returns the listening socket for the request, if there is one.
1252 The caller must close this socket if it is not INVALID_SOCKET.
1253 */
1254 #ifndef NO_INET6
1255 static SOCKET FAR *delete_request(PTInstVar pvar, int request_num,
1256 int *p_num_listening_sockets)
1257 {
1258 #else
1259 static SOCKET delete_request(PTInstVar pvar, int request_num)
1260 {
1261 #endif /* NO_INET6 */
1262 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
1263 #ifndef NO_INET6
1264 SOCKET FAR *lp_listening_sockets;
1265 #else
1266 SOCKET result = INVALID_SOCKET;
1267 #endif /* NO_INET6 */
1268
1269 /* safe to shut down the listening socket here. Any pending connections
1270 that haven't yet been turned into channels will be broken, but that's
1271 just tough luck. */
1272 #ifndef NO_INET6
1273 *p_num_listening_sockets = request->num_listening_sockets;
1274 lp_listening_sockets = request->listening_sockets;
1275 if (request->listening_sockets != NULL) {
1276 request->num_listening_sockets = 0;
1277 request->listening_sockets = NULL;
1278 }
1279
1280 request->status |= FWD_DELETED;
1281
1282 if (request->num_channels == 0) {
1283 really_delete_request(pvar, request_num);
1284 }
1285
1286 return lp_listening_sockets;
1287 #else
1288 if (request->listening_socket != INVALID_SOCKET) {
1289 result = request->listening_socket;
1290 request->listening_socket = INVALID_SOCKET;
1291 }
1292
1293 request->status |= FWD_DELETED;
1294
1295 if (request->num_channels == 0) {
1296 really_delete_request(pvar, request_num);
1297 }
1298
1299 return result;
1300 #endif /* NO_INET6 */
1301 }
1302
1303 static BOOL are_specs_identical(FWDRequestSpec FAR * spec1,
1304 FWDRequestSpec FAR * spec2)
1305 {
1306 return spec1->type == spec2->type
1307 && spec1->from_port == spec2->from_port
1308 && spec1->to_port == spec2->to_port
1309 && strcmp(spec1->to_host, spec2->to_host) == 0
1310 && spec1->check_identity == spec2->check_identity;
1311 }
1312
1313 static BOOL interactive_init_request(PTInstVar pvar, int request_num,
1314 BOOL report_error)
1315 {
1316 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
1317
1318 if (request->spec.type == FWD_LOCAL_TO_REMOTE) {
1319 #ifndef NO_INET6
1320 struct addrinfo hints;
1321 struct addrinfo FAR *res;
1322 struct addrinfo FAR *res0;
1323 SOCKET s;
1324 char pname[NI_MAXSERV];
1325
1326 _snprintf_s(pname, sizeof(pname), _TRUNCATE,
1327 "%d", request->spec.from_port);
1328 memset(&hints, 0, sizeof(hints));
1329 hints.ai_family = AF_UNSPEC; /* a user will be able to specify protocol in future version */
1330 hints.ai_flags = AI_PASSIVE;
1331 hints.ai_socktype = SOCK_STREAM;
1332 if (getaddrinfo(NULL, pname, &hints, &res0))
1333 return FALSE;
1334
1335 /* count number of listening sockets and allocate area for them */
1336 for (request->num_listening_sockets = 0, res = res0; res;
1337 res = res->ai_next)
1338 request->num_listening_sockets++;
1339 request->listening_sockets =
1340 (SOCKET FAR *) malloc(sizeof(SOCKET) *
1341 request->num_listening_sockets);
1342 if (request->listening_sockets == NULL) {
1343 freeaddrinfo(res0);
1344 return FALSE;
1345 }
1346
1347 for (request->num_listening_sockets = 0, res = res0; res;
1348 res = res->ai_next) {
1349 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1350 request->listening_sockets[request->num_listening_sockets++] = s;
1351 if (s == INVALID_SOCKET)
1352 continue;
1353 if (bind(s, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) {
1354 s = INVALID_SOCKET;
1355 continue;
1356 }
1357 if (WSAAsyncSelect
1358 (s, make_accept_wnd(pvar), WM_SOCK_ACCEPT,
1359 FD_ACCEPT | FD_READ | FD_CLOSE | FD_WRITE
1360 ) == SOCKET_ERROR) {
1361 s = INVALID_SOCKET;
1362 continue;
1363 }
1364 if (listen(s, SOMAXCONN) == SOCKET_ERROR) {
1365 s = INVALID_SOCKET;
1366 continue;
1367 }
1368 }
1369 if (s == INVALID_SOCKET) {
1370 if (report_error) {
1371 char buf[256];
1372 UTIL_get_lang_msg("MSG_FWD_SOCKET_ERROR", pvar,
1373 "Some socket(s) required for port forwarding could not be initialized.\n"
1374 "Some port forwarding services may not be available.\n"
1375 "(errno %d)");
1376 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
1377 pvar->ts->UIMsg, WSAGetLastError());
1378 notify_verbose_message(pvar,buf,LOG_LEVEL_WARNING);
1379 }
1380 freeaddrinfo(res0);
1381 /* free(request->listening_sockets); /* DO NOT FREE HERE, listening_sockets'll be freed in FWD_end */
1382 return FALSE;
1383 }
1384 freeaddrinfo(res0);
1385 }
1386
1387 return TRUE;
1388 #else
1389 SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
1390 struct sockaddr_in addr;
1391
1392 addr.sin_family = AF_INET;
1393 addr.sin_port = htons((unsigned short) request->spec.from_port);
1394 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1395
1396 request->listening_socket = s;
1397 if (s == INVALID_SOCKET
1398 || WSAAsyncSelect(s, make_accept_wnd(pvar), WM_SOCK_ACCEPT,
1399 FD_ACCEPT | FD_READ | FD_CLOSE | FD_WRITE) ==
1400 SOCKET_ERROR
1401 || bind(s, (struct sockaddr FAR *) &addr,
1402 sizeof(addr)) == SOCKET_ERROR
1403 || listen(s, SOMAXCONN) == SOCKET_ERROR) {
1404 if (report_error) {
1405 notify_nonfatal_error(pvar,
1406 "Some socket(s) required for port forwarding could not be initialized.\n"
1407 "Some port forwarding services may not be available.");
1408 }
1409 return FALSE;
1410 }
1411 }
1412
1413 return TRUE;
1414 #endif /* NO_INET6 */
1415 }
1416
1417 /* This function will only be called on a request when all its channels are
1418 closed. */
1419 #ifndef NO_INET6
1420 static BOOL init_request(PTInstVar pvar, int request_num,
1421 BOOL report_error, SOCKET FAR * listening_sockets,
1422 int num_listening_sockets)
1423 {
1424 #else
1425 static BOOL init_request(PTInstVar pvar, int request_num,
1426 BOOL report_error, SOCKET listening_socket)
1427 {
1428 #endif /* NO_INET6 */
1429 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
1430
1431 #ifndef NO_INET6
1432 request->num_listening_sockets = 0;
1433 request->listening_sockets = NULL;
1434 request->to_host_addrs = NULL;
1435 request->to_host_lookup_handle = 0;
1436 request->status = 0;
1437
1438 if (pvar->fwd_state.in_interactive_mode) {
1439 if (listening_sockets != NULL) {
1440 request->num_listening_sockets = num_listening_sockets;
1441 request->listening_sockets = listening_sockets;
1442 return TRUE;
1443 } else {
1444 return interactive_init_request(pvar, request_num,
1445 report_error);
1446 }
1447 } else {
1448 assert(listening_sockets == NULL);
1449 return TRUE;
1450 }
1451 #else
1452 request->listening_socket = INVALID_SOCKET;
1453 request->to_host_addr = 0;
1454 request->to_host_hostent_buf = NULL;
1455 request->to_host_lookup_handle = 0;
1456 request->status = 0;
1457
1458 if (pvar->fwd_state.in_interactive_mode) {
1459 if (listening_socket != INVALID_SOCKET) {
1460 request->listening_socket = listening_socket;
1461 return TRUE;
1462 } else {
1463 return interactive_init_request(pvar, request_num,
1464 report_error);
1465 }
1466 } else {
1467 assert(listening_socket == INVALID_SOCKET);
1468 return TRUE;
1469 }
1470 #endif /* NO_INET6 */
1471 }
1472
1473 void FWD_set_request_specs(PTInstVar pvar, FWDRequestSpec FAR * specs,
1474 int num_specs)
1475 {
1476 FWDRequestSpec FAR *new_specs =
1477 (FWDRequestSpec FAR *) malloc(sizeof(FWDRequestSpec) * num_specs);
1478 char FAR *specs_accounted_for;
1479 #ifndef NO_INET6
1480 typedef struct _saved_sockets {
1481 SOCKET FAR *listening_sockets;
1482 int num_listening_sockets;
1483 } saved_sockets_t;
1484 saved_sockets_t FAR *ptr_to_saved_sockets;
1485 #else
1486 SOCKET FAR *saved_sockets;
1487 #endif /* NO_INET6 */
1488 int i;
1489 int num_new_requests = num_specs;
1490 int num_free_requests = 0;
1491 int free_request = 0;
1492 BOOL report_err = TRUE;
1493
1494 memcpy(new_specs, specs, sizeof(FWDRequestSpec) * num_specs);
1495 qsort(new_specs, num_specs, sizeof(FWDRequestSpec), FWD_compare_specs);
1496
1497 for (i = 0; i < num_specs - 1; i++) {
1498 if (FWD_compare_specs(new_specs + i, new_specs + i + 1) == 0) {
1499 UTIL_get_lang_msg("MSG_FWD_DUPLICATE_ERROR", pvar,
1500 "TTSSH INTERNAL ERROR: Could not set port forwards because duplicate type/port requests were found");
1501 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1502 free(new_specs);
1503 return;
1504 }
1505 }
1506
1507 specs_accounted_for = (char FAR *) malloc(sizeof(char) * num_specs);
1508 #ifndef NO_INET6
1509 ptr_to_saved_sockets =
1510 (saved_sockets_t FAR *) malloc(sizeof(saved_sockets_t) *
1511 num_specs);
1512 #else
1513 saved_sockets = (SOCKET FAR *) malloc(sizeof(SOCKET) * num_specs);
1514 #endif /* NO_INET6 */
1515
1516 memset(specs_accounted_for, 0, num_specs);
1517 for (i = 0; i < num_specs; i++) {
1518 #ifndef NO_INET6
1519 ptr_to_saved_sockets[i].listening_sockets = NULL;
1520 ptr_to_saved_sockets[i].num_listening_sockets = 0;
1521 #else
1522 saved_sockets[i] = INVALID_SOCKET;
1523 #endif /* NO_INET6 */
1524 }
1525
1526 for (i = pvar->fwd_state.num_requests - 1; i >= 0; i--) {
1527 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0) {
1528 FWDRequestSpec FAR *cur_spec =
1529 &pvar->fwd_state.requests[i].spec;
1530 FWDRequestSpec FAR *new_spec =
1531 bsearch(cur_spec, new_specs, num_specs,
1532 sizeof(FWDRequestSpec), FWD_compare_specs);
1533
1534 if (new_spec != NULL
1535 && are_specs_identical(cur_spec, new_spec)) {
1536 specs_accounted_for[new_spec - new_specs] = 1;
1537 num_new_requests--;
1538 } else {
1539 #ifndef NO_INET6
1540 int num_listening_sockets;
1541 SOCKET FAR *listening_sockets;
1542 listening_sockets =
1543 delete_request(pvar, i, &num_listening_sockets);
1544 #else
1545 SOCKET listening_socket = delete_request(pvar, i);
1546 #endif /* NO_INET6 */
1547
1548 #ifndef NO_INET6
1549 if (new_spec != NULL) {
1550 ptr_to_saved_sockets[new_spec - new_specs].
1551 listening_sockets = listening_sockets;
1552 ptr_to_saved_sockets[new_spec - new_specs].
1553 num_listening_sockets = num_listening_sockets;
1554 } else if (listening_sockets != NULL) {
1555 /* if there is no new spec(new request), free listening_sockets */
1556 int i;
1557 for (i = 0; i < num_listening_sockets; ++i)
1558 safe_closesocket(pvar, listening_sockets[i]);
1559 }
1560 #else
1561 if (new_spec != NULL) {
1562 saved_sockets[new_spec - new_specs] = listening_socket;
1563 } else if (listening_socket != INVALID_SOCKET) {
1564 safe_closesocket(pvar, listening_socket);
1565 }
1566 #endif /* NO_INET6 */
1567
1568 if (pvar->fwd_state.requests[i].num_channels == 0) {
1569 num_free_requests++;
1570 }
1571 }
1572 } else {
1573 if (pvar->fwd_state.requests[i].num_channels == 0) {
1574 num_free_requests++;
1575 }
1576 }
1577 }
1578
1579 if (num_new_requests > num_free_requests) {
1580 int total_requests =
1581 pvar->fwd_state.num_requests + num_new_requests - num_free_requests;
1582
1583 pvar->fwd_state.requests =
1584 (FWDRequest FAR *) realloc(pvar->fwd_state.requests,
1585 sizeof(FWDRequest) *
1586 total_requests);
1587 for (i = pvar->fwd_state.num_requests; i < total_requests; i++) {
1588 pvar->fwd_state.requests[i].status = FWD_DELETED;
1589 pvar->fwd_state.requests[i].num_channels = 0;
1590 }
1591 pvar->fwd_state.num_requests = total_requests;
1592 }
1593
1594 for (i = 0; i < num_specs; i++) {
1595 if (!specs_accounted_for[i]) {
1596 while ((pvar->fwd_state.requests[free_request].status & FWD_DELETED) == 0
1597 || pvar->fwd_state.requests[free_request].num_channels != 0) {
1598 free_request++;
1599 }
1600
1601 assert(free_request < pvar->fwd_state.num_requests);
1602
1603 pvar->fwd_state.requests[free_request].spec = new_specs[i];
1604 #ifndef NO_INET6
1605 if (!init_request(pvar, free_request, report_err,
1606 ptr_to_saved_sockets[i].listening_sockets,
1607 ptr_to_saved_sockets[i].num_listening_sockets)) {
1608 #else
1609 if (!init_request
1610 (pvar, free_request, report_err, saved_sockets[i])) {
1611 #endif /* NO_INET6 */
1612 report_err = FALSE;
1613 }
1614
1615 free_request++;
1616 }
1617 }
1618
1619 #ifndef NO_INET6
1620 free(ptr_to_saved_sockets);
1621 #else
1622 free(saved_sockets);
1623 #endif /* NO_INET6 */
1624 free(specs_accounted_for);
1625 free(new_specs);
1626 }
1627
1628 void FWD_prep_forwarding(PTInstVar pvar)
1629 {
1630 int i;
1631 int num_server_listening_requests = 0;
1632
1633 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1634 FWDRequest FAR *request = pvar->fwd_state.requests + i;
1635
1636 if ((request->status & FWD_DELETED) == 0) {
1637 switch (request->spec.type) {
1638 case FWD_REMOTE_TO_LOCAL:
1639 SSH_request_forwarding(pvar, request->spec.from_port,
1640 request->spec.to_host,
1641 request->spec.to_port);
1642 num_server_listening_requests++;
1643 break;
1644 case FWD_REMOTE_X11_TO_LOCAL:{
1645 int screen_num = request->spec.to_port - 6000;
1646
1647 pvar->fwd_state.X11_auth_data =
1648 X11_load_local_auth_data(screen_num);
1649 SSH_request_X11_forwarding(pvar,
1650 X11_get_spoofed_protocol_name
1651 (pvar->fwd_state.X11_auth_data),
1652 X11_get_spoofed_protocol_data
1653 (pvar->fwd_state.X11_auth_data),
1654 X11_get_spoofed_protocol_data_len
1655 (pvar->fwd_state.X11_auth_data),
1656 screen_num);
1657 num_server_listening_requests++;
1658 break;
1659 }
1660 }
1661 }
1662 }
1663
1664 pvar->fwd_state.num_server_listening_specs =
1665 num_server_listening_requests;
1666
1667 if (num_server_listening_requests > 0) {
1668 FWDRequestSpec FAR *server_listening_requests =
1669 (FWDRequestSpec FAR *) malloc(sizeof(FWDRequestSpec) *
1670 num_server_listening_requests);
1671
1672 pvar->fwd_state.server_listening_specs = server_listening_requests;
1673
1674 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1675 if ((pvar->fwd_state.requests[i].status & FWD_DELETED) == 0) {
1676 switch (pvar->fwd_state.requests[i].spec.type) {
1677 case FWD_REMOTE_X11_TO_LOCAL:
1678 case FWD_REMOTE_TO_LOCAL:
1679 *server_listening_requests =
1680 pvar->fwd_state.requests[i].spec;
1681 server_listening_requests++;
1682 break;
1683 }
1684 }
1685 }
1686
1687 /* No two server-side request specs can have the same port. */
1688 qsort(pvar->fwd_state.server_listening_specs,
1689 num_server_listening_requests, sizeof(FWDRequestSpec),
1690 FWD_compare_specs);
1691 }
1692 }
1693
1694 void FWD_enter_interactive_mode(PTInstVar pvar)
1695 {
1696 BOOL report_error = TRUE;
1697 int i;
1698
1699 pvar->fwd_state.in_interactive_mode = TRUE;
1700
1701 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1702 if (!interactive_init_request(pvar, i, report_error)) {
1703 report_error = FALSE;
1704 }
1705 }
1706 }
1707
1708 static void create_local_channel(PTInstVar pvar, uint32 remote_channel_num,
1709 int request_num, void *filter_closure,
1710 FWDFilter filter, int *chan_num)
1711 {
1712 char buf[1024];
1713 int channel_num;
1714 FWDChannel FAR *channel;
1715 FWDRequest FAR *request = pvar->fwd_state.requests + request_num;
1716 #ifndef NO_INET6
1717 struct addrinfo hints;
1718 char pname[NI_MAXSERV];
1719 #endif /* NO_INET6 */
1720
1721 #ifndef NO_INET6
1722 if (request->to_host_addrs == NULL
1723 && request->to_host_lookup_handle == 0) {
1724 HANDLE task_handle;
1725 #else
1726 if (request->to_host_addr == 0 && request->to_host_lookup_handle == 0) {
1727 HANDLE task_handle;
1728 #endif /* NO_INET6 */
1729
1730 #ifdef NO_INET6
1731 if (request->to_host_hostent_buf == NULL) {
1732 request->to_host_hostent_buf =
1733 (char FAR *) malloc(MAXGETHOSTSTRUCT);
1734 }
1735 #endif /* NO_INET6 */
1736
1737 #ifndef NO_INET6
1738 _snprintf_s(pname, sizeof(pname), _TRUNCATE, "%d", request->spec.to_port);
1739 memset(&hints, 0, sizeof(hints));
1740 hints.ai_family = AF_UNSPEC;
1741 hints.ai_socktype = SOCK_STREAM;
1742 task_handle =
1743 WSAAsyncGetAddrInfo(make_accept_wnd(pvar), WM_SOCK_GOTNAME,
1744 request->spec.to_host, pname, &hints,
1745 &request->to_host_addrs);
1746 #else
1747 task_handle =
1748 WSAAsyncGetHostByName(make_accept_wnd(pvar), WM_SOCK_GOTNAME,
1749 request->spec.to_host,
1750 request->to_host_hostent_buf,
1751 MAXGETHOSTSTRUCT);
1752 #endif /* NO_INET6 */
1753
1754 if (task_handle == 0) {
1755 SSH_fail_channel_open(pvar, remote_channel_num);
1756 UTIL_get_lang_msg("MSG_FWD_DENIED_HANDLE_ERROR", pvar,
1757 "The server attempted to forward a connection through this machine.\n"
1758 "It requested a connection to machine %s on port %s.\n"
1759 "An error occurred while processing the request, and it has been denied.");
1760 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
1761 pvar->ts->UIMsg,
1762 request->spec.to_host, request->spec.to_port_name);
1763 notify_nonfatal_error(pvar, buf);
1764 #ifndef NO_INET6
1765 /*****/
1766 freeaddrinfo(request->to_host_addrs);
1767 #else
1768 free(request->to_host_hostent_buf);
1769 request->to_host_hostent_buf = NULL;
1770 #endif /* NO_INET6 */
1771 return;
1772 } else {
1773 request->to_host_lookup_handle = task_handle;
1774 }
1775 }
1776
1777 channel_num = alloc_channel(pvar, FWD_REMOTE_CONNECTED, request_num);
1778 channel = pvar->fwd_state.channels + channel_num;
1779
1780 channel->remote_num = remote_channel_num;
1781 channel->filter_closure = filter_closure;
1782 channel->filter = filter;
1783
1784 // (2008.12.5 maya)
1785 channel->type = TYPE_PORTFWD;
1786
1787 // save channel number (2005.7.2 yutaka)
1788 if (chan_num != NULL) {
1789 *chan_num = channel_num;
1790 }
1791
1792 #ifndef NO_INET6
1793 if (request->to_host_addrs != NULL) {
1794 make_local_connection(pvar, channel_num);
1795 }
1796 #else
1797 if (request->to_host_addr != 0) {
1798 make_local_connection(pvar, channel_num);
1799 }
1800 #endif /* NO_INET6 */
1801 }
1802
1803 void FWD_open(PTInstVar pvar, uint32 remote_channel_num,
1804 char FAR * local_hostname, int local_port,
1805 char FAR * originator, int originator_len,
1806 int *chan_num)
1807 {
1808 int i;
1809 char buf[1024];
1810
1811 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1812 FWDRequest FAR *request = pvar->fwd_state.requests + i;
1813
1814 if (SSHv1(pvar)) {
1815 if ((request->status & FWD_DELETED) == 0
1816 && request->spec.type == FWD_REMOTE_TO_LOCAL
1817 && request->spec.to_port == local_port
1818 && strcmp(request->spec.to_host, local_hostname) == 0) {
1819 create_local_channel(pvar, remote_channel_num, i, NULL, NULL, chan_num);
1820 return;
1821 }
1822
1823 } else { // SSH2
1824 if ((request->status & FWD_DELETED) == 0
1825 && request->spec.type == FWD_REMOTE_TO_LOCAL
1826 && request->spec.from_port == local_port
1827 // && strcmp(request->spec.to_host, local_hostname) == 0) {
1828 ) {
1829 create_local_channel(pvar, remote_channel_num, i, NULL, NULL, chan_num);
1830 return;
1831 }
1832 }
1833 }
1834
1835 SSH_fail_channel_open(pvar, remote_channel_num);
1836
1837 /* now, before we panic, maybe we TOLD the server we could forward this port
1838 and then the user changed the settings. */
1839 for (i = 0; i < pvar->fwd_state.num_server_listening_specs; i++) {
1840 FWDRequestSpec FAR *spec =
1841 pvar->fwd_state.server_listening_specs + i;
1842
1843 if (spec->type == FWD_REMOTE_TO_LOCAL
1844 && spec->to_port == local_port
1845 && strcmp(spec->to_host, local_hostname) == 0) {
1846 return; /* no error message needed. The user just turned this off, that's all */
1847 }
1848 }
1849
1850 /* this forwarding was not prespecified */
1851 UTIL_get_lang_msg("MSG_FWD_DENIED_ERROR", pvar,
1852 "The server attempted to forward a connection through this machine.\n"
1853 "It requested a connection to machine %s on port %d.\n"
1854 "You did not specify this forwarding to TTSSH in advance, and therefore the request was denied.");
1855 _snprintf_s(buf, sizeof(buf), _TRUNCATE,
1856 pvar->ts->UIMsg,
1857 local_hostname, local_port);
1858 notify_nonfatal_error(pvar, buf);
1859 }
1860
1861 void FWD_X11_open(PTInstVar pvar, uint32 remote_channel_num,
1862 char FAR * originator, int originator_len,
1863 int *chan_num)
1864 {
1865 int i;
1866
1867 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
1868 FWDRequest FAR *request = pvar->fwd_state.requests + i;
1869
1870 if ((request->status & FWD_DELETED) == 0
1871 && request->spec.type == FWD_REMOTE_X11_TO_LOCAL) {
1872 create_local_channel(pvar, remote_channel_num, i,
1873 X11_init_unspoofing_filter(pvar,
1874 pvar->fwd_state.
1875 X11_auth_data),
1876 X11_unspoofing_filter,
1877 chan_num);
1878 return;
1879 }
1880 }
1881
1882 SSH_fail_channel_open(pvar, remote_channel_num);
1883
1884 /* now, before we panic, maybe we TOLD the server we could forward this port
1885 and then the user changed the settings. */
1886 for (i = 0; i < pvar->fwd_state.num_server_listening_specs; i++) {
1887 FWDRequestSpec FAR *spec =
1888 pvar->fwd_state.server_listening_specs + i;
1889
1890 if (spec->type == FWD_REMOTE_X11_TO_LOCAL) {
1891 return; /* no error message needed. The user just turned this off, that's all */
1892 }
1893 }
1894
1895 /* this forwarding was not prespecified */
1896 UTIL_get_lang_msg("MSG_FWD_DENIED_X_ERROR", pvar,
1897 "The server attempted to forward a connection through this machine.\n"
1898 "It requested a connection to the local X server.\n"
1899 "You did not specify this forwarding to TTSSH in advance, and therefore the request was denied.");
1900 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1901 }
1902
1903 // agent forwarding ���v���������AFWDChannel ����������
1904 // SSH1 ������������������
1905 int FWD_agent_open(PTInstVar pvar, uint32 remote_channel_num)
1906 {
1907 if (SSHv1(pvar)) {
1908 return alloc_agent_channel(pvar, remote_channel_num);
1909 }
1910
1911 return -1;
1912 }
1913
1914 void FWD_confirmed_open(PTInstVar pvar, uint32 local_channel_num,
1915 uint32 remote_channel_num)
1916 {
1917 SOCKET s;
1918 FWDChannel FAR *channel;
1919
1920 if (!FWD_check_local_channel_num(pvar, local_channel_num))
1921 return;
1922
1923 channel = pvar->fwd_state.channels + local_channel_num;
1924 s = channel->local_socket;
1925 if (s != INVALID_SOCKET) {
1926 channel->remote_num = remote_channel_num;
1927 channel->status |= FWD_REMOTE_CONNECTED;
1928
1929 read_local_connection(pvar, local_channel_num);
1930 } else {
1931 SSH_channel_input_eof(pvar, remote_channel_num, local_channel_num);
1932 SSH_channel_output_eof(pvar, remote_channel_num);
1933 channel->status |= FWD_CLOSED_LOCAL_IN | FWD_CLOSED_LOCAL_OUT;
1934 }
1935 }
1936
1937 void FWD_failed_open(PTInstVar pvar, uint32 local_channel_num)
1938 {
1939 if (!FWD_check_local_channel_num(pvar, local_channel_num))
1940 return;
1941
1942 UTIL_get_lang_msg("MSG_FWD_DENIED_BY_SERVER_ERROR", pvar,
1943 "A program on the local machine attempted to connect to a forwarded port.\n"
1944 "The forwarding request was denied by the server. The connection has been closed.");
1945 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1946 FWD_free_channel(pvar, local_channel_num);
1947 }
1948
1949 static BOOL blocking_write(PTInstVar pvar, SOCKET s, const char FAR * data,
1950 int length)
1951 {
1952 u_long do_block = 0;
1953
1954 #if 0
1955 return (pvar->PWSAAsyncSelect) (s, make_accept_wnd(pvar), 0,
1956 0) == SOCKET_ERROR
1957 || ioctlsocket(s, FIONBIO, &do_block) == SOCKET_ERROR
1958 || (pvar->Psend) (s, data, length, 0) != length
1959 || (pvar->PWSAAsyncSelect) (s, pvar->fwd_state.accept_wnd,
1960 WM_SOCK_ACCEPT,
1961 FD_READ | FD_CLOSE | FD_WRITE) == SOCKET_ERROR;
1962 #else
1963 if ( (pvar->PWSAAsyncSelect) (s, make_accept_wnd(pvar), 0, 0) == SOCKET_ERROR ) {
1964 goto error;
1965 }
1966
1967 if ( ioctlsocket(s, FIONBIO, &do_block) == SOCKET_ERROR ) {
1968 goto error;
1969 }
1970
1971 if ( (pvar->Psend) (s, data, length, 0) != length ) {
1972 goto error;
1973 }
1974
1975 if ( (pvar->PWSAAsyncSelect) (s, pvar->fwd_state.accept_wnd,
1976 WM_SOCK_ACCEPT,
1977 FD_READ | FD_CLOSE | FD_WRITE) == SOCKET_ERROR ) {
1978 goto error;
1979 }
1980
1981 return (TRUE);
1982
1983 error:
1984 return (FALSE);
1985 #endif
1986 }
1987
1988 void FWD_received_data(PTInstVar pvar, uint32 local_channel_num,
1989 unsigned char FAR * data, int length)
1990 {
1991 SOCKET s;
1992 FWDChannel FAR *channel;
1993 int action = FWD_FILTER_RETAIN;
1994
1995 if (!FWD_check_local_channel_num(pvar, local_channel_num))
1996 return;
1997
1998 channel = pvar->fwd_state.channels + local_channel_num;
1999
2000 if (channel->filter != NULL) {
2001 action =
2002 channel->filter(channel->filter_closure,
2003 FWD_FILTER_FROM_SERVER, &length, &data);
2004 }
2005
2006 s = channel->local_socket;
2007 if (length > 0 && s != INVALID_SOCKET) {
2008 if (!UTIL_sock_buffered_write
2009 (pvar, &channel->writebuf, blocking_write, s, data, length)) {
2010 closed_local_connection(pvar, local_channel_num);
2011 UTIL_get_lang_msg("MSG_FWD_COMM_ERROR", pvar,
2012 "A communications error occurred while sending forwarded data to a local port.\n"
2013 "The forwarded connection will be closed.");
2014 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
2015 }
2016 }
2017
2018 switch (action) {
2019 case FWD_FILTER_REMOVE:
2020 channel->filter(channel->filter_closure, 0, NULL, NULL);
2021 channel->filter = NULL;
2022 channel->filter_closure = NULL;
2023 break;
2024 case FWD_FILTER_CLOSECHANNEL:
2025 closed_local_connection(pvar, local_channel_num);
2026 break;
2027 }
2028 }
2029
2030 void FWD_init(PTInstVar pvar)
2031 {
2032 pvar->fwd_state.requests = NULL;
2033 pvar->fwd_state.num_requests = 0;
2034 pvar->fwd_state.num_server_listening_specs = -1; /* forwarding prep not yet done */
2035 pvar->fwd_state.server_listening_specs = NULL;
2036 pvar->fwd_state.num_channels = 0;
2037 pvar->fwd_state.channels = NULL;
2038 pvar->fwd_state.local_host_IP_numbers = NULL;
2039 pvar->fwd_state.X11_auth_data = NULL;
2040 pvar->fwd_state.accept_wnd = NULL;
2041 pvar->fwd_state.in_interactive_mode = FALSE;
2042 }
2043
2044 void FWD_end(PTInstVar pvar)
2045 {
2046 int i;
2047
2048 if (pvar->fwd_state.channels != NULL) {
2049 for (i = 0; i < pvar->fwd_state.num_channels; i++) {
2050 FWD_free_channel(pvar, i);
2051 }
2052 free(pvar->fwd_state.channels);
2053 }
2054 #ifndef NO_INET6
2055 if (pvar->fwd_state.requests != NULL) {
2056 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
2057 int j;
2058 int num_listening_sockets;
2059 SOCKET FAR *s =
2060 delete_request(pvar, i, &num_listening_sockets);
2061
2062 for (j = 0; j < num_listening_sockets; ++j) {
2063 if (s[j] != INVALID_SOCKET)
2064 closesocket(s[j]);
2065 }
2066 if (s != NULL)
2067 free(s); /* free(request[i]->listening_sockets) */
2068 }
2069 free(pvar->fwd_state.requests);
2070 }
2071 #else
2072 if (pvar->fwd_state.requests != NULL) {
2073 for (i = 0; i < pvar->fwd_state.num_requests; i++) {
2074 SOCKET s = delete_request(pvar, i);
2075
2076 if (s != INVALID_SOCKET) {
2077 closesocket(s);
2078 }
2079 }
2080 free(pvar->fwd_state.requests);
2081 }
2082 #endif /* NO_INET6 */
2083
2084 free(pvar->fwd_state.local_host_IP_numbers);
2085 free(pvar->fwd_state.server_listening_specs);
2086
2087 if (pvar->fwd_state.X11_auth_data != NULL) {
2088 X11_dispose_auth_data(pvar->fwd_state.X11_auth_data);
2089 }
2090
2091 if (pvar->fwd_state.accept_wnd != NULL) {
2092 DestroyWindow(pvar->fwd_state.accept_wnd);
2093 }
2094 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26