Develop and Download Open Source Software

Browse Subversion Repository

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10618 - (show annotations) (download) (as text)
Fri Mar 3 15:15:16 2023 UTC (14 months, 3 weeks ago) by zmatsuo
File MIME type: text/x-csrc
File size: 64286 byte(s)
ttxsshで tttset.UIMsg[] ではなく TInstVar.UIMsg[] を使用するよう修正

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

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