OSDN Git Service

Change behavior of automatic IPv4/IPv6 selection.
[ffftp/ffftp.git] / socketwrapper.c
1 // socketwrapper.c\r
2 // Copyright (C) 2011 Suguru Kawamoto\r
3 // ソケットラッパー\r
4 // socket関連関数をOpenSSL用に置換\r
5 // socket関連関数のIPv6対応\r
6 // コンパイルにはOpenSSLのヘッダーファイルが必要\r
7 // 実行にはOpenSSLのDLLが必要\r
8 \r
9 #include <ws2tcpip.h>\r
10 #include <windows.h>\r
11 #include <mmsystem.h>\r
12 #include <openssl/ssl.h>\r
13 \r
14 #include "socketwrapper.h"\r
15 #include "protectprocess.h"\r
16 #include "mbswrapper.h"\r
17 #include "punycode.h"\r
18 \r
19 // FTPS対応\r
20 \r
21 typedef void (__cdecl* _SSL_load_error_strings)();\r
22 typedef int (__cdecl* _SSL_library_init)();\r
23 typedef SSL_METHOD* (__cdecl* _SSLv23_method)();\r
24 typedef SSL_CTX* (__cdecl* _SSL_CTX_new)(SSL_METHOD*);\r
25 typedef void (__cdecl* _SSL_CTX_free)(SSL_CTX*);\r
26 typedef SSL* (__cdecl* _SSL_new)(SSL_CTX*);\r
27 typedef void (__cdecl* _SSL_free)(SSL*);\r
28 typedef int (__cdecl* _SSL_shutdown)(SSL*);\r
29 typedef int (__cdecl* _SSL_get_fd)(SSL*);\r
30 typedef int (__cdecl* _SSL_set_fd)(SSL*, int);\r
31 typedef int (__cdecl* _SSL_accept)(SSL*);\r
32 typedef int (__cdecl* _SSL_connect)(SSL*);\r
33 typedef int (__cdecl* _SSL_write)(SSL*, const void*, int);\r
34 typedef int (__cdecl* _SSL_peek)(SSL*, void*, int);\r
35 typedef int (__cdecl* _SSL_read)(SSL*, void*, int);\r
36 typedef int (__cdecl* _SSL_get_error)(SSL*, int);\r
37 typedef X509* (__cdecl* _SSL_get_peer_certificate)(const SSL*);\r
38 typedef long (__cdecl* _SSL_get_verify_result)(const SSL*);\r
39 typedef SSL_SESSION* (__cdecl* _SSL_get_session)(SSL*);\r
40 typedef int (__cdecl* _SSL_set_session)(SSL*, SSL_SESSION*);\r
41 typedef X509_STORE* (__cdecl* _SSL_CTX_get_cert_store)(const SSL_CTX*);\r
42 typedef BIO_METHOD* (__cdecl* _BIO_s_mem)();\r
43 typedef BIO* (__cdecl* _BIO_new)(BIO_METHOD*);\r
44 typedef int (__cdecl* _BIO_free)(BIO*);\r
45 typedef BIO* (__cdecl* _BIO_new_mem_buf)(void*, int);\r
46 typedef long (__cdecl* _BIO_ctrl)(BIO*, int, long, void*);\r
47 typedef void (__cdecl* _X509_free)(X509*);\r
48 typedef int (__cdecl* _X509_print_ex)(BIO*, X509*, unsigned long, unsigned long);\r
49 typedef X509_NAME* (__cdecl* _X509_get_subject_name)(X509*);\r
50 typedef int (__cdecl* _X509_NAME_print_ex)(BIO*, X509_NAME*, int, unsigned long);\r
51 typedef X509* (__cdecl* _PEM_read_bio_X509)(BIO*, X509**, pem_password_cb*, void*);\r
52 typedef int (__cdecl* _X509_STORE_add_cert)(X509_STORE*, X509*);\r
53 \r
54 _SSL_load_error_strings p_SSL_load_error_strings;\r
55 _SSL_library_init p_SSL_library_init;\r
56 _SSLv23_method p_SSLv23_method;\r
57 _SSL_CTX_new p_SSL_CTX_new;\r
58 _SSL_CTX_free p_SSL_CTX_free;\r
59 _SSL_new p_SSL_new;\r
60 _SSL_free p_SSL_free;\r
61 _SSL_shutdown p_SSL_shutdown;\r
62 _SSL_get_fd p_SSL_get_fd;\r
63 _SSL_set_fd p_SSL_set_fd;\r
64 _SSL_accept p_SSL_accept;\r
65 _SSL_connect p_SSL_connect;\r
66 _SSL_write p_SSL_write;\r
67 _SSL_peek p_SSL_peek;\r
68 _SSL_read p_SSL_read;\r
69 _SSL_get_error p_SSL_get_error;\r
70 _SSL_get_peer_certificate p_SSL_get_peer_certificate;\r
71 _SSL_get_verify_result p_SSL_get_verify_result;\r
72 _SSL_get_session p_SSL_get_session;\r
73 _SSL_set_session p_SSL_set_session;\r
74 _SSL_CTX_get_cert_store p_SSL_CTX_get_cert_store;\r
75 _BIO_s_mem p_BIO_s_mem;\r
76 _BIO_new p_BIO_new;\r
77 _BIO_free p_BIO_free;\r
78 _BIO_new_mem_buf p_BIO_new_mem_buf;\r
79 _BIO_ctrl p_BIO_ctrl;\r
80 _X509_free p_X509_free;\r
81 _X509_print_ex p_X509_print_ex;\r
82 _X509_get_subject_name p_X509_get_subject_name;\r
83 _X509_NAME_print_ex p_X509_NAME_print_ex;\r
84 _PEM_read_bio_X509 p_PEM_read_bio_X509;\r
85 _X509_STORE_add_cert p_X509_STORE_add_cert;\r
86 \r
87 #define MAX_SSL_SOCKET 16\r
88 \r
89 BOOL g_bOpenSSLLoaded;\r
90 HMODULE g_hOpenSSL;\r
91 HMODULE g_hOpenSSLCommon;\r
92 CRITICAL_SECTION g_OpenSSLLock;\r
93 DWORD g_OpenSSLTimeout;\r
94 LPSSLTIMEOUTCALLBACK g_pOpenSSLTimeoutCallback;\r
95 LPSSLCONFIRMCALLBACK g_pOpenSSLConfirmCallback;\r
96 SSL_CTX* g_pOpenSSLCTX;\r
97 SSL* g_pOpenSSLHandle[MAX_SSL_SOCKET];\r
98 \r
99 BOOL __stdcall DefaultSSLTimeoutCallback(BOOL* pbAborted)\r
100 {\r
101         Sleep(100);\r
102         return *pbAborted;\r
103 }\r
104 \r
105 BOOL __stdcall DefaultSSLConfirmCallback(BOOL* pbAborted, BOOL bVerified, LPCSTR Certificate, LPCSTR CommonName)\r
106 {\r
107         return bVerified;\r
108 }\r
109 \r
110 // OpenSSLを初期化\r
111 BOOL LoadOpenSSL()\r
112 {\r
113         if(g_bOpenSSLLoaded)\r
114                 return FALSE;\r
115 #ifdef ENABLE_PROCESS_PROTECTION\r
116         // 同梱するOpenSSLのバージョンに合わせてSHA1ハッシュ値を変更すること\r
117         // ssleay32.dll 1.0.0g\r
118         // libssl32.dll 1.0.0g\r
119         RegisterTrustedModuleSHA1Hash("\x42\x32\x3E\x44\x35\xBC\x98\x6C\x45\xC9\xA2\xB8\x41\xE7\xDA\x7B\x6A\x98\xB2\x28");\r
120         // libeay32.dll 1.0.0g\r
121         RegisterTrustedModuleSHA1Hash("\x3F\xC8\x07\x84\xB3\xF0\x71\x4A\x18\x59\x52\x1F\x99\x09\x65\xB9\x49\xA7\x15\x36");\r
122 #endif\r
123         g_hOpenSSL = LoadLibrary("ssleay32.dll");\r
124         // バージョン固定のためlibssl32.dllの読み込みは脆弱性の原因になり得るので廃止\r
125 //      if(!g_hOpenSSL)\r
126 //              g_hOpenSSL = LoadLibrary("libssl32.dll");\r
127         if(!g_hOpenSSL\r
128                 || !(p_SSL_load_error_strings = (_SSL_load_error_strings)GetProcAddress(g_hOpenSSL, "SSL_load_error_strings"))\r
129                 || !(p_SSL_library_init = (_SSL_library_init)GetProcAddress(g_hOpenSSL, "SSL_library_init"))\r
130                 || !(p_SSLv23_method = (_SSLv23_method)GetProcAddress(g_hOpenSSL, "SSLv23_method"))\r
131                 || !(p_SSL_CTX_new = (_SSL_CTX_new)GetProcAddress(g_hOpenSSL, "SSL_CTX_new"))\r
132                 || !(p_SSL_CTX_free = (_SSL_CTX_free)GetProcAddress(g_hOpenSSL, "SSL_CTX_free"))\r
133                 || !(p_SSL_new = (_SSL_new)GetProcAddress(g_hOpenSSL, "SSL_new"))\r
134                 || !(p_SSL_free = (_SSL_free)GetProcAddress(g_hOpenSSL, "SSL_free"))\r
135                 || !(p_SSL_shutdown = (_SSL_shutdown)GetProcAddress(g_hOpenSSL, "SSL_shutdown"))\r
136                 || !(p_SSL_get_fd = (_SSL_get_fd)GetProcAddress(g_hOpenSSL, "SSL_get_fd"))\r
137                 || !(p_SSL_set_fd = (_SSL_set_fd)GetProcAddress(g_hOpenSSL, "SSL_set_fd"))\r
138                 || !(p_SSL_accept = (_SSL_accept)GetProcAddress(g_hOpenSSL, "SSL_accept"))\r
139                 || !(p_SSL_connect = (_SSL_connect)GetProcAddress(g_hOpenSSL, "SSL_connect"))\r
140                 || !(p_SSL_write = (_SSL_write)GetProcAddress(g_hOpenSSL, "SSL_write"))\r
141                 || !(p_SSL_peek = (_SSL_peek)GetProcAddress(g_hOpenSSL, "SSL_peek"))\r
142                 || !(p_SSL_read = (_SSL_read)GetProcAddress(g_hOpenSSL, "SSL_read"))\r
143                 || !(p_SSL_get_error = (_SSL_get_error)GetProcAddress(g_hOpenSSL, "SSL_get_error"))\r
144                 || !(p_SSL_get_peer_certificate = (_SSL_get_peer_certificate)GetProcAddress(g_hOpenSSL, "SSL_get_peer_certificate"))\r
145                 || !(p_SSL_get_verify_result = (_SSL_get_verify_result)GetProcAddress(g_hOpenSSL, "SSL_get_verify_result"))\r
146                 || !(p_SSL_get_session = (_SSL_get_session)GetProcAddress(g_hOpenSSL, "SSL_get_session"))\r
147                 || !(p_SSL_set_session = (_SSL_set_session)GetProcAddress(g_hOpenSSL, "SSL_set_session"))\r
148                 || !(p_SSL_CTX_get_cert_store = (_SSL_CTX_get_cert_store)GetProcAddress(g_hOpenSSL, "SSL_CTX_get_cert_store")))\r
149         {\r
150                 if(g_hOpenSSL)\r
151                         FreeLibrary(g_hOpenSSL);\r
152                 g_hOpenSSL = NULL;\r
153                 return FALSE;\r
154         }\r
155         g_hOpenSSLCommon = LoadLibrary("libeay32.dll");\r
156         if(!g_hOpenSSLCommon\r
157                 || !(p_BIO_s_mem = (_BIO_s_mem)GetProcAddress(g_hOpenSSLCommon, "BIO_s_mem"))\r
158                 || !(p_BIO_new = (_BIO_new)GetProcAddress(g_hOpenSSLCommon, "BIO_new"))\r
159                 || !(p_BIO_free = (_BIO_free)GetProcAddress(g_hOpenSSLCommon, "BIO_free"))\r
160                 || !(p_BIO_new_mem_buf = (_BIO_new_mem_buf)GetProcAddress(g_hOpenSSLCommon, "BIO_new_mem_buf"))\r
161                 || !(p_BIO_ctrl = (_BIO_ctrl)GetProcAddress(g_hOpenSSLCommon, "BIO_ctrl"))\r
162                 || !(p_X509_free = (_X509_free)GetProcAddress(g_hOpenSSLCommon, "X509_free"))\r
163                 || !(p_X509_print_ex = (_X509_print_ex)GetProcAddress(g_hOpenSSLCommon, "X509_print_ex"))\r
164                 || !(p_X509_get_subject_name = (_X509_get_subject_name)GetProcAddress(g_hOpenSSLCommon, "X509_get_subject_name"))\r
165                 || !(p_X509_NAME_print_ex = (_X509_NAME_print_ex)GetProcAddress(g_hOpenSSLCommon, "X509_NAME_print_ex"))\r
166                 || !(p_PEM_read_bio_X509 = (_PEM_read_bio_X509)GetProcAddress(g_hOpenSSLCommon, "PEM_read_bio_X509"))\r
167                 || !(p_X509_STORE_add_cert = (_X509_STORE_add_cert)GetProcAddress(g_hOpenSSLCommon, "X509_STORE_add_cert")))\r
168         {\r
169                 if(g_hOpenSSL)\r
170                         FreeLibrary(g_hOpenSSL);\r
171                 g_hOpenSSL = NULL;\r
172                 if(g_hOpenSSLCommon)\r
173                         FreeLibrary(g_hOpenSSLCommon);\r
174                 g_hOpenSSLCommon = NULL;\r
175                 return FALSE;\r
176         }\r
177         InitializeCriticalSection(&g_OpenSSLLock);\r
178         p_SSL_load_error_strings();\r
179         p_SSL_library_init();\r
180         SetSSLTimeoutCallback(60000, DefaultSSLTimeoutCallback);\r
181         SetSSLConfirmCallback(DefaultSSLConfirmCallback);\r
182         g_bOpenSSLLoaded = TRUE;\r
183         return TRUE;\r
184 }\r
185 \r
186 // OpenSSLを解放\r
187 void FreeOpenSSL()\r
188 {\r
189         int i;\r
190         if(!g_bOpenSSLLoaded)\r
191                 return;\r
192         EnterCriticalSection(&g_OpenSSLLock);\r
193         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
194         {\r
195                 if(g_pOpenSSLHandle[i])\r
196                 {\r
197                         p_SSL_shutdown(g_pOpenSSLHandle[i]);\r
198                         p_SSL_free(g_pOpenSSLHandle[i]);\r
199                         g_pOpenSSLHandle[i] = NULL;\r
200                 }\r
201         }\r
202         if(g_pOpenSSLCTX)\r
203                 p_SSL_CTX_free(g_pOpenSSLCTX);\r
204         g_pOpenSSLCTX = NULL;\r
205         FreeLibrary(g_hOpenSSL);\r
206         g_hOpenSSL = NULL;\r
207         FreeLibrary(g_hOpenSSLCommon);\r
208         g_hOpenSSLCommon = NULL;\r
209         LeaveCriticalSection(&g_OpenSSLLock);\r
210         DeleteCriticalSection(&g_OpenSSLLock);\r
211         g_bOpenSSLLoaded = FALSE;\r
212 }\r
213 \r
214 // OpenSSLが使用可能かどうか確認\r
215 BOOL IsOpenSSLLoaded()\r
216 {\r
217         return g_bOpenSSLLoaded;\r
218 }\r
219 \r
220 SSL** GetUnusedSSLPointer()\r
221 {\r
222         int i;\r
223         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
224         {\r
225                 if(!g_pOpenSSLHandle[i])\r
226                         return &g_pOpenSSLHandle[i];\r
227         }\r
228         return NULL;\r
229 }\r
230 \r
231 SSL** FindSSLPointerFromSocket(SOCKET s)\r
232 {\r
233         int i;\r
234         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
235         {\r
236                 if(g_pOpenSSLHandle[i])\r
237                 {\r
238                         if(p_SSL_get_fd(g_pOpenSSLHandle[i]) == s)\r
239                                 return &g_pOpenSSLHandle[i];\r
240                 }\r
241         }\r
242         return NULL;\r
243 }\r
244 \r
245 BOOL ConfirmSSLCertificate(SSL* pSSL, BOOL* pbAborted)\r
246 {\r
247         BOOL bResult;\r
248         BOOL bVerified;\r
249         char* pData;\r
250         char* pSubject;\r
251         X509* pX509;\r
252         BIO* pBIO;\r
253         long Length;\r
254         char* pBuffer;\r
255         char* pCN;\r
256         char* p;\r
257         bResult = FALSE;\r
258         bVerified = FALSE;\r
259         pData = NULL;\r
260         pSubject = NULL;\r
261         if(pX509 = p_SSL_get_peer_certificate(pSSL))\r
262         {\r
263                 if(pBIO = p_BIO_new(p_BIO_s_mem()))\r
264                 {\r
265                         p_X509_print_ex(pBIO, pX509, 0, XN_FLAG_RFC2253);\r
266                         if((Length = p_BIO_ctrl(pBIO, BIO_CTRL_INFO, 0, &pBuffer)) > 0)\r
267                         {\r
268                                 if(pData = (char*)malloc(Length + sizeof(char)))\r
269                                 {\r
270                                         memcpy(pData, pBuffer, Length);\r
271                                         *(char*)((size_t)pData + Length) = '\0';\r
272                                 }\r
273                         }\r
274                         p_BIO_free(pBIO);\r
275                 }\r
276                 if(pBIO = p_BIO_new(p_BIO_s_mem()))\r
277                 {\r
278                         p_X509_NAME_print_ex(pBIO, p_X509_get_subject_name(pX509), 0, XN_FLAG_RFC2253);\r
279                         if((Length = p_BIO_ctrl(pBIO, BIO_CTRL_INFO, 0, &pBuffer)) > 0)\r
280                         {\r
281                                 if(pSubject = (char*)malloc(Length + sizeof(char)))\r
282                                 {\r
283                                         memcpy(pSubject, pBuffer, Length);\r
284                                         *(char*)((size_t)pSubject + Length) = '\0';\r
285                                 }\r
286                         }\r
287                         p_BIO_free(pBIO);\r
288                 }\r
289                 p_X509_free(pX509);\r
290         }\r
291         if(pX509 && p_SSL_get_verify_result(pSSL) == X509_V_OK)\r
292                 bVerified = TRUE;\r
293         pCN = pSubject;\r
294         while(pCN)\r
295         {\r
296                 if(strncmp(pCN, "CN=", strlen("CN=")) == 0)\r
297                 {\r
298                         pCN += strlen("CN=");\r
299                         if(p = strchr(pCN, ','))\r
300                                 *p = '\0';\r
301                         break;\r
302                 }\r
303                 if(pCN = strchr(pCN, ','))\r
304                         pCN++;\r
305         }\r
306         bResult = g_pOpenSSLConfirmCallback(pbAborted, bVerified, pData, pCN);\r
307         if(pData)\r
308                 free(pData);\r
309         if(pSubject)\r
310                 free(pSubject);\r
311         return bResult;\r
312 }\r
313 \r
314 void SetSSLTimeoutCallback(DWORD Timeout, LPSSLTIMEOUTCALLBACK pCallback)\r
315 {\r
316         if(!g_bOpenSSLLoaded)\r
317                 return;\r
318         EnterCriticalSection(&g_OpenSSLLock);\r
319         g_OpenSSLTimeout = Timeout;\r
320         g_pOpenSSLTimeoutCallback = pCallback;\r
321         LeaveCriticalSection(&g_OpenSSLLock);\r
322 }\r
323 \r
324 void SetSSLConfirmCallback(LPSSLCONFIRMCALLBACK pCallback)\r
325 {\r
326         if(!g_bOpenSSLLoaded)\r
327                 return;\r
328         EnterCriticalSection(&g_OpenSSLLock);\r
329         g_pOpenSSLConfirmCallback = pCallback;\r
330         LeaveCriticalSection(&g_OpenSSLLock);\r
331 }\r
332 \r
333 // SSLルート証明書を設定\r
334 // PEM形式のみ指定可能\r
335 BOOL SetSSLRootCertificate(const void* pData, DWORD Length)\r
336 {\r
337         BOOL r;\r
338         X509_STORE* pStore;\r
339         BYTE* p;\r
340         BYTE* pBegin;\r
341         BYTE* pEnd;\r
342         BIO* pBIO;\r
343         X509* pX509;\r
344         if(!g_bOpenSSLLoaded)\r
345                 return FALSE;\r
346         r = FALSE;\r
347         EnterCriticalSection(&g_OpenSSLLock);\r
348         if(!g_pOpenSSLCTX)\r
349                 g_pOpenSSLCTX = p_SSL_CTX_new(p_SSLv23_method());\r
350         if(g_pOpenSSLCTX)\r
351         {\r
352                 if(pStore = p_SSL_CTX_get_cert_store(g_pOpenSSLCTX))\r
353                 {\r
354                         p = (BYTE*)pData;\r
355                         pBegin = NULL;\r
356                         pEnd = NULL;\r
357                         while(Length > 0)\r
358                         {\r
359                                 if(!pBegin)\r
360                                 {\r
361                                         if(Length < 27)\r
362                                                 break;\r
363                                         if(memcmp(p, "-----BEGIN CERTIFICATE-----", 27) == 0)\r
364                                                 pBegin = p;\r
365                                 }\r
366                                 else if(!pEnd)\r
367                                 {\r
368                                         if(Length < 25)\r
369                                                 break;\r
370                                         if(memcmp(p, "-----END CERTIFICATE-----", 25) == 0)\r
371                                                 pEnd = p + 25;\r
372                                 }\r
373                                 if(pBegin && pEnd)\r
374                                 {\r
375                                         if(pBIO = p_BIO_new_mem_buf(pBegin, (int)((size_t)pEnd - (size_t)pBegin)))\r
376                                         {\r
377                                                 if(pX509 = p_PEM_read_bio_X509(pBIO, NULL, NULL, NULL))\r
378                                                 {\r
379                                                         if(p_X509_STORE_add_cert(pStore, pX509) == 1)\r
380                                                                 r = TRUE;\r
381                                                         p_X509_free(pX509);\r
382                                                 }\r
383                                                 p_BIO_free(pBIO);\r
384                                         }\r
385                                         pBegin = NULL;\r
386                                         pEnd = NULL;\r
387                                 }\r
388                                 p++;\r
389                                 Length--;\r
390                         }\r
391                 }\r
392         }\r
393         LeaveCriticalSection(&g_OpenSSLLock);\r
394         return r;\r
395 }\r
396 \r
397 // ワイルドカードの比較\r
398 // 主にSSL証明書のCN確認用\r
399 BOOL IsHostNameMatched(LPCSTR HostName, LPCSTR CommonName)\r
400 {\r
401         BOOL bResult;\r
402         const char* pAsterisk;\r
403         size_t BeforeAsterisk;\r
404         const char* pBeginAsterisk;\r
405         const char* pEndAsterisk;\r
406         const char* pDot;\r
407         bResult = FALSE;\r
408         if(HostName && CommonName)\r
409         {\r
410                 if(pAsterisk = strchr(CommonName, '*'))\r
411                 {\r
412                         BeforeAsterisk = ((size_t)pAsterisk - (size_t)CommonName) / sizeof(char);\r
413                         pBeginAsterisk = HostName + BeforeAsterisk;\r
414                         while(*pAsterisk == '*')\r
415                         {\r
416                                 pAsterisk++;\r
417                         }\r
418                         pEndAsterisk = HostName + strlen(HostName) - strlen(pAsterisk);\r
419                         // "*"より前は大文字小文字を無視して完全一致\r
420                         if(_strnicmp(HostName, CommonName, BeforeAsterisk) == 0)\r
421                         {\r
422                                 // "*"より後は大文字小文字を無視して完全一致\r
423                                 if(_stricmp(pEndAsterisk, pAsterisk) == 0)\r
424                                 {\r
425                                         // "*"と一致する範囲に"."が含まれてはならない\r
426                                         pDot = strchr(pBeginAsterisk, '.');\r
427                                         if(!pDot || pDot >= pEndAsterisk)\r
428                                                 bResult = TRUE;\r
429                                 }\r
430                         }\r
431                 }\r
432                 else if(_stricmp(HostName, CommonName) == 0)\r
433                         bResult = TRUE;\r
434         }\r
435         return bResult;\r
436 }\r
437 \r
438 // SSLセッションを開始\r
439 BOOL AttachSSL(SOCKET s, SOCKET parent, BOOL* pbAborted)\r
440 {\r
441         BOOL r;\r
442         DWORD Time;\r
443         SSL** ppSSL;\r
444         SSL** ppSSLParent;\r
445         SSL_SESSION* pSession;\r
446         int Return;\r
447         int Error;\r
448         if(!g_bOpenSSLLoaded)\r
449                 return FALSE;\r
450         r = FALSE;\r
451         Time = timeGetTime();\r
452         EnterCriticalSection(&g_OpenSSLLock);\r
453         if(!g_pOpenSSLCTX)\r
454                 g_pOpenSSLCTX = p_SSL_CTX_new(p_SSLv23_method());\r
455         if(g_pOpenSSLCTX)\r
456         {\r
457                 if(ppSSL = GetUnusedSSLPointer())\r
458                 {\r
459                         if(*ppSSL = p_SSL_new(g_pOpenSSLCTX))\r
460                         {\r
461                                 if(p_SSL_set_fd(*ppSSL, s) != 0)\r
462                                 {\r
463                                         if(parent != INVALID_SOCKET)\r
464                                         {\r
465                                                 if(ppSSLParent = FindSSLPointerFromSocket(parent))\r
466                                                 {\r
467                                                         if(pSession = p_SSL_get_session(*ppSSLParent))\r
468                                                         {\r
469                                                                 if(p_SSL_set_session(*ppSSL, pSession) == 1)\r
470                                                                 {\r
471                                                                 }\r
472                                                         }\r
473                                                 }\r
474                                         }\r
475                                         // SSLのネゴシエーションには時間がかかる場合がある\r
476                                         r = TRUE;\r
477                                         while(r)\r
478                                         {\r
479                                                 Return = p_SSL_connect(*ppSSL);\r
480                                                 if(Return == 1)\r
481                                                         break;\r
482                                                 Error = p_SSL_get_error(*ppSSL, Return);\r
483                                                 if(Error == SSL_ERROR_WANT_READ || Error == SSL_ERROR_WANT_WRITE)\r
484                                                 {\r
485                                                         LeaveCriticalSection(&g_OpenSSLLock);\r
486                                                         if(g_pOpenSSLTimeoutCallback(pbAborted) || (g_OpenSSLTimeout > 0 && timeGetTime() - Time >= g_OpenSSLTimeout))\r
487                                                                 r = FALSE;\r
488                                                         EnterCriticalSection(&g_OpenSSLLock);\r
489                                                 }\r
490                                                 else\r
491                                                         r = FALSE;\r
492                                         }\r
493                                         if(r)\r
494                                         {\r
495                                                 if(ConfirmSSLCertificate(*ppSSL, pbAborted))\r
496                                                 {\r
497                                                 }\r
498                                                 else\r
499                                                 {\r
500                                                         LeaveCriticalSection(&g_OpenSSLLock);\r
501                                                         DetachSSL(s);\r
502                                                         r = FALSE;\r
503                                                         EnterCriticalSection(&g_OpenSSLLock);\r
504                                                 }\r
505                                         }\r
506                                         else\r
507                                         {\r
508                                                 LeaveCriticalSection(&g_OpenSSLLock);\r
509                                                 DetachSSL(s);\r
510                                                 EnterCriticalSection(&g_OpenSSLLock);\r
511                                         }\r
512                                 }\r
513                                 else\r
514                                 {\r
515                                         LeaveCriticalSection(&g_OpenSSLLock);\r
516                                         DetachSSL(s);\r
517                                         EnterCriticalSection(&g_OpenSSLLock);\r
518                                 }\r
519                         }\r
520                 }\r
521         }\r
522         LeaveCriticalSection(&g_OpenSSLLock);\r
523         return r;\r
524 }\r
525 \r
526 // SSLセッションを終了\r
527 BOOL DetachSSL(SOCKET s)\r
528 {\r
529         BOOL r;\r
530         SSL** ppSSL;\r
531         if(!g_bOpenSSLLoaded)\r
532                 return FALSE;\r
533         r = FALSE;\r
534         EnterCriticalSection(&g_OpenSSLLock);\r
535         if(ppSSL = FindSSLPointerFromSocket(s))\r
536         {\r
537                 p_SSL_shutdown(*ppSSL);\r
538                 p_SSL_free(*ppSSL);\r
539                 *ppSSL = NULL;\r
540                 r = TRUE;\r
541         }\r
542         LeaveCriticalSection(&g_OpenSSLLock);\r
543         return r;\r
544 }\r
545 \r
546 // SSLとしてマークされているか確認\r
547 // マークされていればTRUEを返す\r
548 BOOL IsSSLAttached(SOCKET s)\r
549 {\r
550         SSL** ppSSL;\r
551         if(!g_bOpenSSLLoaded)\r
552                 return FALSE;\r
553         EnterCriticalSection(&g_OpenSSLLock);\r
554         ppSSL = FindSSLPointerFromSocket(s);\r
555         LeaveCriticalSection(&g_OpenSSLLock);\r
556         if(!ppSSL)\r
557                 return FALSE;\r
558         return TRUE;\r
559 }\r
560 \r
561 SOCKET FTPS_socket(int af, int type, int protocol)\r
562 {\r
563         return socket(af, type, protocol);\r
564 }\r
565 \r
566 int FTPS_bind(SOCKET s, const struct sockaddr *addr, int namelen)\r
567 {\r
568         return bind(s, addr, namelen);\r
569 }\r
570 \r
571 int FTPS_listen(SOCKET s, int backlog)\r
572 {\r
573         return listen(s, backlog);\r
574 }\r
575 \r
576 // accept相当の関数\r
577 // ただし初めからSSLのネゴシエーションを行う\r
578 SOCKET FTPS_accept(SOCKET s, struct sockaddr *addr, int *addrlen)\r
579 {\r
580         SOCKET r;\r
581         BOOL bAborted;\r
582         r = accept(s, addr, addrlen);\r
583         bAborted = FALSE;\r
584         if(!AttachSSL(r, INVALID_SOCKET, &bAborted))\r
585         {\r
586                 closesocket(r);\r
587                 return INVALID_SOCKET;\r
588         }\r
589         return r;\r
590 }\r
591 \r
592 // connect相当の関数\r
593 // ただし初めからSSLのネゴシエーションを行う\r
594 int FTPS_connect(SOCKET s, const struct sockaddr *name, int namelen)\r
595 {\r
596         int r;\r
597         BOOL bAborted;\r
598         r = connect(s, name, namelen);\r
599         bAborted = FALSE;\r
600         if(!AttachSSL(r, INVALID_SOCKET, &bAborted))\r
601                 return SOCKET_ERROR;\r
602         return r;\r
603 }\r
604 \r
605 // closesocket相当の関数\r
606 int FTPS_closesocket(SOCKET s)\r
607 {\r
608         DetachSSL(s);\r
609         return closesocket(s);\r
610 }\r
611 \r
612 // send相当の関数\r
613 int FTPS_send(SOCKET s, const char * buf, int len, int flags)\r
614 {\r
615         SSL** ppSSL;\r
616         if(!g_bOpenSSLLoaded)\r
617                 return send(s, buf, len, flags);\r
618         EnterCriticalSection(&g_OpenSSLLock);\r
619         ppSSL = FindSSLPointerFromSocket(s);\r
620         LeaveCriticalSection(&g_OpenSSLLock);\r
621         if(!ppSSL)\r
622                 return send(s, buf, len, flags);\r
623         return p_SSL_write(*ppSSL, buf, len);\r
624 }\r
625 \r
626 // recv相当の関数\r
627 int FTPS_recv(SOCKET s, char * buf, int len, int flags)\r
628 {\r
629         SSL** ppSSL;\r
630         if(!g_bOpenSSLLoaded)\r
631                 return recv(s, buf, len, flags);\r
632         EnterCriticalSection(&g_OpenSSLLock);\r
633         ppSSL = FindSSLPointerFromSocket(s);\r
634         LeaveCriticalSection(&g_OpenSSLLock);\r
635         if(!ppSSL)\r
636                 return recv(s, buf, len, flags);\r
637         if(flags & MSG_PEEK)\r
638                 return p_SSL_peek(*ppSSL, buf, len);\r
639         return p_SSL_read(*ppSSL, buf, len);\r
640 }\r
641 \r
642 // IPv6対応\r
643 \r
644 typedef struct\r
645 {\r
646         HANDLE h;\r
647         HWND hWnd;\r
648         u_int wMsg;\r
649         char * name;\r
650         char * buf;\r
651         int buflen;\r
652         short Family;\r
653 } GETHOSTBYNAMEDATA;\r
654 \r
655 DWORD WINAPI WSAAsyncGetHostByNameIPv6ThreadProc(LPVOID lpParameter)\r
656 {\r
657         GETHOSTBYNAMEDATA* pData;\r
658         struct hostent* pHost;\r
659         struct addrinfo* pAddr;\r
660         struct addrinfo* p;\r
661         pHost = NULL;\r
662         pData = (GETHOSTBYNAMEDATA*)lpParameter;\r
663         if(getaddrinfo(pData->name, NULL, NULL, &pAddr) == 0)\r
664         {\r
665                 p = pAddr;\r
666                 while(p)\r
667                 {\r
668                         if(p->ai_family == pData->Family)\r
669                         {\r
670                                 switch(p->ai_family)\r
671                                 {\r
672                                 case AF_INET:\r
673                                         pHost = (struct hostent*)pData->buf;\r
674                                         if((size_t)pData->buflen >= sizeof(struct hostent) + sizeof(char*) * 2 + sizeof(struct in_addr)\r
675                                                 && p->ai_addrlen >= sizeof(struct sockaddr_in))\r
676                                         {\r
677                                                 pHost->h_name = NULL;\r
678                                                 pHost->h_aliases = NULL;\r
679                                                 pHost->h_addrtype = p->ai_family;\r
680                                                 pHost->h_length = sizeof(struct in_addr);\r
681                                                 pHost->h_addr_list = (char**)(&pHost[1]);\r
682                                                 pHost->h_addr_list[0] = (char*)(&pHost->h_addr_list[2]);\r
683                                                 pHost->h_addr_list[1] = NULL;\r
684                                                 memcpy(pHost->h_addr_list[0], &((struct sockaddr_in*)p->ai_addr)->sin_addr, sizeof(struct in_addr));\r
685                                                 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(sizeof(struct hostent) + sizeof(char*) * 2 + p->ai_addrlen));\r
686                                         }\r
687                                         else\r
688                                                 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(WSAENOBUFS << 16));\r
689                                         break;\r
690                                 case AF_INET6:\r
691                                         pHost = (struct hostent*)pData->buf;\r
692                                         if((size_t)pData->buflen >= sizeof(struct hostent) + sizeof(char*) * 2 + sizeof(struct in6_addr)\r
693                                                 && p->ai_addrlen >= sizeof(struct sockaddr_in6))\r
694                                         {\r
695                                                 pHost->h_name = NULL;\r
696                                                 pHost->h_aliases = NULL;\r
697                                                 pHost->h_addrtype = p->ai_family;\r
698                                                 pHost->h_length = sizeof(struct in6_addr);\r
699                                                 pHost->h_addr_list = (char**)(&pHost[1]);\r
700                                                 pHost->h_addr_list[0] = (char*)(&pHost->h_addr_list[2]);\r
701                                                 pHost->h_addr_list[1] = NULL;\r
702                                                 memcpy(pHost->h_addr_list[0], &((struct sockaddr_in6*)p->ai_addr)->sin6_addr, sizeof(struct in6_addr));\r
703                                                 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(sizeof(struct hostent) + sizeof(char*) * 2 + p->ai_addrlen));\r
704                                         }\r
705                                         else\r
706                                                 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(WSAENOBUFS << 16));\r
707                                         break;\r
708                                 }\r
709                         }\r
710                         if(pHost)\r
711                                 break;\r
712                         p = p->ai_next;\r
713                 }\r
714                 if(!p)\r
715                         PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(ERROR_INVALID_FUNCTION << 16));\r
716                 freeaddrinfo(pAddr);\r
717         }\r
718         else\r
719                 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(ERROR_INVALID_FUNCTION << 16));\r
720         // CreateThreadが返すハンドルが重複するのを回避\r
721         Sleep(10000);\r
722         CloseHandle(pData->h);\r
723         free(pData->name);\r
724         free(pData);\r
725         return 0;\r
726 }\r
727 \r
728 // IPv6対応のWSAAsyncGetHostByName相当の関数\r
729 // FamilyにはAF_INETまたはAF_INET6を指定可能\r
730 // ただしANSI用\r
731 HANDLE WSAAsyncGetHostByNameIPv6(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family)\r
732 {\r
733         HANDLE hResult;\r
734         GETHOSTBYNAMEDATA* pData;\r
735         hResult = NULL;\r
736         if(pData = malloc(sizeof(GETHOSTBYNAMEDATA)))\r
737         {\r
738                 pData->hWnd = hWnd;\r
739                 pData->wMsg = wMsg;\r
740                 if(pData->name = malloc(sizeof(char) * (strlen(name) + 1)))\r
741                 {\r
742                         strcpy(pData->name, name);\r
743                         pData->buf = buf;\r
744                         pData->buflen = buflen;\r
745                         pData->Family = Family;\r
746                         if(pData->h = CreateThread(NULL, 0, WSAAsyncGetHostByNameIPv6ThreadProc, pData, CREATE_SUSPENDED, NULL))\r
747                         {\r
748                                 ResumeThread(pData->h);\r
749                                 hResult = pData->h;\r
750                         }\r
751                 }\r
752         }\r
753         if(!hResult)\r
754         {\r
755                 if(pData)\r
756                 {\r
757                         if(pData->name)\r
758                                 free(pData->name);\r
759                         free(pData);\r
760                 }\r
761         }\r
762         return hResult;\r
763 }\r
764 \r
765 // WSAAsyncGetHostByNameIPv6用のWSACancelAsyncRequest相当の関数\r
766 int WSACancelAsyncRequestIPv6(HANDLE hAsyncTaskHandle)\r
767 {\r
768         int Result;\r
769         Result = SOCKET_ERROR;\r
770         if(TerminateThread(hAsyncTaskHandle, 0))\r
771                 Result = 0;\r
772         return Result;\r
773 }\r
774 \r
775 char* AddressToStringIPv6(char* str, void* in6)\r
776 {\r
777         char* pResult;\r
778         unsigned char* p;\r
779         int MaxZero;\r
780         int MaxZeroLen;\r
781         int i;\r
782         int j;\r
783         char Tmp[5];\r
784         pResult = str;\r
785         p = (unsigned char*)in6;\r
786         MaxZero = 8;\r
787         MaxZeroLen = 1;\r
788         for(i = 0; i < 8; i++)\r
789         {\r
790                 for(j = i; j < 8; j++)\r
791                 {\r
792                         if(p[j * 2] != 0 || p[j * 2 + 1] != 0)\r
793                                 break;\r
794                 }\r
795                 if(j - i > MaxZeroLen)\r
796                 {\r
797                         MaxZero = i;\r
798                         MaxZeroLen = j - i;\r
799                 }\r
800         }\r
801         strcpy(str, "");\r
802         for(i = 0; i < 8; i++)\r
803         {\r
804                 if(i == MaxZero)\r
805                 {\r
806                         if(i == 0)\r
807                                 strcat(str, ":");\r
808                         strcat(str, ":");\r
809                 }\r
810                 else if(i < MaxZero || i >= MaxZero + MaxZeroLen)\r
811                 {\r
812                         sprintf(Tmp, "%x", (((int)p[i * 2] & 0xff) << 8) | ((int)p[i * 2 + 1] & 0xff));\r
813                         strcat(str, Tmp);\r
814                         if(i < 7)\r
815                                 strcat(str, ":");\r
816                 }\r
817         }\r
818         return pResult;\r
819 }\r
820 \r
821 // IPv6対応のinet_ntoa相当の関数\r
822 // ただしANSI用\r
823 char* inet6_ntoa(struct in6_addr in6)\r
824 {\r
825         char* pResult;\r
826         static char Adrs[40];\r
827         pResult = NULL;\r
828         memset(Adrs, 0, sizeof(Adrs));\r
829         pResult = AddressToStringIPv6(Adrs, &in6);\r
830         return pResult;\r
831 }\r
832 \r
833 // IPv6対応のinet_addr相当の関数\r
834 // ただしANSI用\r
835 struct in6_addr inet6_addr(const char* cp)\r
836 {\r
837         struct in6_addr Result;\r
838         int AfterZero;\r
839         int i;\r
840         char* p;\r
841         memset(&Result, 0, sizeof(Result));\r
842         AfterZero = 0;\r
843         for(i = 0; i < 8; i++)\r
844         {\r
845                 if(!cp)\r
846                 {\r
847                         memset(&Result, 0xff, sizeof(Result));\r
848                         break;\r
849                 }\r
850                 if(i >= AfterZero)\r
851                 {\r
852                         if(strncmp(cp, ":", 1) == 0)\r
853                         {\r
854                                 cp = cp + 1;\r
855                                 if(i == 0 && strncmp(cp, ":", 1) == 0)\r
856                                         cp = cp + 1;\r
857                                 p = (char*)cp;\r
858                                 AfterZero = 7;\r
859                                 while(p = strstr(p, ":"))\r
860                                 {\r
861                                         p = p + 1;\r
862                                         AfterZero--;\r
863                                 }\r
864                         }\r
865                         else\r
866                         {\r
867                                 Result.u.Word[i] = (USHORT)strtol(cp, &p, 16);\r
868                                 Result.u.Word[i] = ((Result.u.Word[i] & 0xff00) >> 8) | ((Result.u.Word[i] & 0x00ff) << 8);\r
869                                 if(strncmp(p, ":", 1) != 0 && strlen(p) > 0)\r
870                                 {\r
871                                         memset(&Result, 0xff, sizeof(Result));\r
872                                         break;\r
873                                 }\r
874                                 if(cp = strstr(cp, ":"))\r
875                                         cp = cp + 1;\r
876                         }\r
877                 }\r
878         }\r
879         return Result;\r
880 }\r
881 \r
882 BOOL ConvertDomainNameToPunycode(LPSTR Output, DWORD Count, LPCSTR Input)\r
883 {\r
884         BOOL bResult;\r
885         punycode_uint* pUnicode;\r
886         punycode_uint* p;\r
887         BOOL bNeeded;\r
888         LPCSTR InputString;\r
889         punycode_uint Length;\r
890         punycode_uint OutputLength;\r
891         bResult = FALSE;\r
892         if(pUnicode = malloc(sizeof(punycode_uint) * strlen(Input)))\r
893         {\r
894                 p = pUnicode;\r
895                 bNeeded = FALSE;\r
896                 InputString = Input;\r
897                 Length = 0;\r
898                 while(*InputString != '\0')\r
899                 {\r
900                         *p = (punycode_uint)GetNextCharM(InputString, &InputString);\r
901                         if(*p >= 0x80)\r
902                                 bNeeded = TRUE;\r
903                         p++;\r
904                         Length++;\r
905                 }\r
906                 if(bNeeded)\r
907                 {\r
908                         if(Count >= strlen("xn--") + 1)\r
909                         {\r
910                                 strcpy(Output, "xn--");\r
911                                 OutputLength = Count - strlen("xn--");\r
912                                 if(punycode_encode(Length, pUnicode, NULL, (punycode_uint*)&OutputLength, Output + strlen("xn--")) == punycode_success)\r
913                                 {\r
914                                         Output[strlen("xn--") + OutputLength] = '\0';\r
915                                         bResult = TRUE;\r
916                                 }\r
917                         }\r
918                 }\r
919                 free(pUnicode);\r
920         }\r
921         if(!bResult)\r
922         {\r
923                 if(Count >= strlen(Input) + 1)\r
924                 {\r
925                         strcpy(Output, Input);\r
926                         bResult = TRUE;\r
927                 }\r
928         }\r
929         return bResult;\r
930 }\r
931 \r
932 BOOL ConvertNameToPunycode(LPSTR Output, LPCSTR Input)\r
933 {\r
934         BOOL bResult;\r
935         DWORD Length;\r
936         char* pm0;\r
937         char* pm1;\r
938         char* p;\r
939         char* pNext;\r
940         bResult = FALSE;\r
941         Length = strlen(Input);\r
942         if(pm0 = AllocateStringM(Length + 1))\r
943         {\r
944                 if(pm1 = AllocateStringM(Length * 4 + 1))\r
945                 {\r
946                         strcpy(pm0, Input);\r
947                         p = pm0;\r
948                         while(p)\r
949                         {\r
950                                 if(pNext = strchr(p, '.'))\r
951                                 {\r
952                                         *pNext = '\0';\r
953                                         pNext++;\r
954                                 }\r
955                                 if(ConvertDomainNameToPunycode(pm1, Length * 4, p))\r
956                                         strcat(Output, pm1);\r
957                                 if(pNext)\r
958                                         strcat(Output, ".");\r
959                                 p = pNext;\r
960                         }\r
961                         bResult = TRUE;\r
962                         FreeDuplicatedString(pm1);\r
963                 }\r
964                 FreeDuplicatedString(pm0);\r
965         }\r
966         return bResult;\r
967 }\r
968 \r
969 HANDLE WSAAsyncGetHostByNameM(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen)\r
970 {\r
971         HANDLE r = NULL;\r
972         char* pa0 = NULL;\r
973         if(pa0 = AllocateStringA(strlen(name) * 4))\r
974         {\r
975                 if(ConvertNameToPunycode(pa0, name))\r
976                         r = WSAAsyncGetHostByName(hWnd, wMsg, pa0, buf, buflen);\r
977         }\r
978         FreeDuplicatedString(pa0);\r
979         return r;\r
980 }\r
981 \r
982 HANDLE WSAAsyncGetHostByNameIPv6M(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family)\r
983 {\r
984         HANDLE r = NULL;\r
985         char* pa0 = NULL;\r
986         if(pa0 = AllocateStringA(strlen(name) * 4))\r
987         {\r
988                 if(ConvertNameToPunycode(pa0, name))\r
989                         r = WSAAsyncGetHostByNameIPv6(hWnd, wMsg, pa0, buf, buflen, Family);\r
990         }\r
991         FreeDuplicatedString(pa0);\r
992         return r;\r
993 }\r
994 \r
995 // SFTP対応\r
996 \r
997 typedef void* (__cdecl* _SFTP_Create)();\r
998 typedef void (__cdecl* _SFTP_Destroy)(void*);\r
999 typedef BOOL (__cdecl* _SFTP_IsExited)(void*);\r
1000 typedef BOOL (__cdecl* _SFTP_SetTimeoutCallback)(void*, void*);\r
1001 typedef size_t (__cdecl* _SFTP_PeekStdOut)(void*, void*, size_t);\r
1002 typedef size_t (__cdecl* _SFTP_ReadStdOut)(void*, void*, size_t);\r
1003 typedef size_t (__cdecl* _SFTP_WriteStdIn)(void*, const void*, size_t);\r
1004 typedef size_t (__cdecl* _SFTP_PeekDataOut)(void*, void*, size_t);\r
1005 typedef size_t (__cdecl* _SFTP_ReadDataOut)(void*, void*, size_t);\r
1006 typedef size_t (__cdecl* _SFTP_WriteDataIn)(void*, const void*, size_t);\r
1007 typedef BOOL (__cdecl* _SFTP_SetFilePosition)(void*, LONGLONG);\r
1008 \r
1009 _SFTP_Create p_SFTP_Create;\r
1010 _SFTP_Destroy p_SFTP_Destroy;\r
1011 _SFTP_IsExited p_SFTP_IsExited;\r
1012 _SFTP_SetTimeoutCallback p_SFTP_SetTimeoutCallback;\r
1013 _SFTP_PeekStdOut p_SFTP_PeekStdOut;\r
1014 _SFTP_ReadStdOut p_SFTP_ReadStdOut;\r
1015 _SFTP_WriteStdIn p_SFTP_WriteStdIn;\r
1016 _SFTP_PeekDataOut p_SFTP_PeekDataOut;\r
1017 _SFTP_ReadDataOut p_SFTP_ReadDataOut;\r
1018 _SFTP_WriteDataIn p_SFTP_WriteDataIn;\r
1019 _SFTP_SetFilePosition p_SFTP_SetFilePosition;\r
1020 \r
1021 typedef struct\r
1022 {\r
1023         SOCKET Control;\r
1024         SOCKET Data;\r
1025         void* Handle;\r
1026         char Host[1024];\r
1027         int Port;\r
1028         char User[1024];\r
1029         char Password[1024];\r
1030 } SFTPDATA;\r
1031 \r
1032 #define MAX_SFTP_SOCKET 16\r
1033 \r
1034 BOOL g_bPuTTYLoaded;\r
1035 HMODULE g_hPuTTY;\r
1036 CRITICAL_SECTION g_PuTTYLock;\r
1037 SFTPDATA g_SFTPData[MAX_SFTP_SOCKET];\r
1038 \r
1039 // PuTTYを初期化\r
1040 BOOL LoadPuTTY()\r
1041 {\r
1042         int i;\r
1043         if(g_bPuTTYLoaded)\r
1044                 return FALSE;\r
1045 #ifdef ENABLE_PROCESS_PROTECTION\r
1046         // ビルドしたputty.dllに合わせてSHA1ハッシュ値を変更すること\r
1047         RegisterTrustedModuleSHA1Hash("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");\r
1048 #endif\r
1049         // デバッグ用\r
1050 #ifdef _DEBUG\r
1051         {\r
1052                 char Path[MAX_PATH];\r
1053                 GetModuleFileName(NULL, Path, MAX_PATH);\r
1054                 strcpy(strrchr(Path, '\\'), "\\..\\putty\\Debug\\PuTTY.dll");\r
1055                 g_hPuTTY = LoadLibrary(Path);\r
1056         }\r
1057 #else\r
1058         g_hPuTTY = LoadLibrary("putty.dll");\r
1059 #endif\r
1060         if(!g_hPuTTY\r
1061                 || !(p_SFTP_Create = (_SFTP_Create)GetProcAddress(g_hPuTTY, "SFTP_Create"))\r
1062                 || !(p_SFTP_Destroy = (_SFTP_Destroy)GetProcAddress(g_hPuTTY, "SFTP_Destroy"))\r
1063                 || !(p_SFTP_IsExited = (_SFTP_IsExited)GetProcAddress(g_hPuTTY, "SFTP_IsExited"))\r
1064                 || !(p_SFTP_SetTimeoutCallback = (_SFTP_SetTimeoutCallback)GetProcAddress(g_hPuTTY, "SFTP_SetTimeoutCallback"))\r
1065                 || !(p_SFTP_PeekStdOut = (_SFTP_PeekStdOut)GetProcAddress(g_hPuTTY, "SFTP_PeekStdOut"))\r
1066                 || !(p_SFTP_ReadStdOut = (_SFTP_ReadStdOut)GetProcAddress(g_hPuTTY, "SFTP_ReadStdOut"))\r
1067                 || !(p_SFTP_WriteStdIn = (_SFTP_WriteStdIn)GetProcAddress(g_hPuTTY, "SFTP_WriteStdIn"))\r
1068                 || !(p_SFTP_PeekDataOut = (_SFTP_PeekDataOut)GetProcAddress(g_hPuTTY, "SFTP_PeekDataOut"))\r
1069                 || !(p_SFTP_ReadDataOut = (_SFTP_ReadDataOut)GetProcAddress(g_hPuTTY, "SFTP_ReadDataOut"))\r
1070                 || !(p_SFTP_WriteDataIn = (_SFTP_WriteDataIn)GetProcAddress(g_hPuTTY, "SFTP_WriteDataIn"))\r
1071                 || !(p_SFTP_SetFilePosition = (_SFTP_SetFilePosition)GetProcAddress(g_hPuTTY, "SFTP_SetFilePosition")))\r
1072         {\r
1073                 if(g_hPuTTY)\r
1074                         FreeLibrary(g_hPuTTY);\r
1075                 g_hPuTTY = NULL;\r
1076                 return FALSE;\r
1077         }\r
1078         for(i = 0; i < MAX_SFTP_SOCKET; i++)\r
1079         {\r
1080                 g_SFTPData[i].Control = INVALID_SOCKET;\r
1081                 g_SFTPData[i].Data = INVALID_SOCKET;\r
1082         }\r
1083         InitializeCriticalSection(&g_PuTTYLock);\r
1084         g_bPuTTYLoaded = TRUE;\r
1085         return TRUE;\r
1086 }\r
1087 \r
1088 // PuTTYを解放\r
1089 void FreePuTTY()\r
1090 {\r
1091         int i;\r
1092         if(!g_bPuTTYLoaded)\r
1093                 return;\r
1094         EnterCriticalSection(&g_PuTTYLock);\r
1095         for(i = 0; i < MAX_SFTP_SOCKET; i++)\r
1096         {\r
1097                 if(g_SFTPData[i].Control != INVALID_SOCKET)\r
1098                 {\r
1099                         closesocket(g_SFTPData[i].Control);\r
1100                         g_SFTPData[i].Control = INVALID_SOCKET;\r
1101                         p_SFTP_Destroy(g_SFTPData[i].Handle);\r
1102                 }\r
1103                 if(g_SFTPData[i].Data != INVALID_SOCKET)\r
1104                 {\r
1105                         closesocket(g_SFTPData[i].Data);\r
1106                         g_SFTPData[i].Data = INVALID_SOCKET;\r
1107                 }\r
1108         }\r
1109         FreeLibrary(g_hPuTTY);\r
1110         g_hPuTTY = NULL;\r
1111         LeaveCriticalSection(&g_PuTTYLock);\r
1112         DeleteCriticalSection(&g_PuTTYLock);\r
1113         g_bPuTTYLoaded = FALSE;\r
1114 }\r
1115 \r
1116 // PuTTYが使用可能かどうか確認\r
1117 BOOL IsPuTTYLoaded()\r
1118 {\r
1119         return g_bPuTTYLoaded;\r
1120 }\r
1121 \r
1122 SFTPDATA* GetUnusedSFTPData()\r
1123 {\r
1124         int i;\r
1125         for(i = 0; i < MAX_SFTP_SOCKET; i++)\r
1126         {\r
1127                 if(g_SFTPData[i].Control == INVALID_SOCKET)\r
1128                 {\r
1129                         memset(&g_SFTPData[i], 0, sizeof(SFTPDATA));\r
1130                         return &g_SFTPData[i];\r
1131                 }\r
1132         }\r
1133         return NULL;\r
1134 }\r
1135 \r
1136 SFTPDATA* FindSFTPDataFromSocket(SOCKET s)\r
1137 {\r
1138         int i;\r
1139         for(i = 0; i < MAX_SFTP_SOCKET; i++)\r
1140         {\r
1141                 if(g_SFTPData[i].Control == s || g_SFTPData[i].Data == s)\r
1142                         return &g_SFTPData[i];\r
1143         }\r
1144         return NULL;\r
1145 }\r
1146 \r
1147 // SFTPとしてマークされているか確認\r
1148 // マークされていればTRUEを返す\r
1149 BOOL IsSFTPAttached(SOCKET s)\r
1150 {\r
1151         SFTPDATA* pSFTPData;\r
1152         if(!g_bPuTTYLoaded)\r
1153                 return FALSE;\r
1154         EnterCriticalSection(&g_PuTTYLock);\r
1155         pSFTPData = FindSFTPDataFromSocket(s);\r
1156         LeaveCriticalSection(&g_PuTTYLock);\r
1157         if(!pSFTPData)\r
1158                 return FALSE;\r
1159         return TRUE;\r
1160 }\r
1161 \r
1162 // コントロール用の仮想的なソケットを取得\r
1163 // 識別子としてダミーのソケットを返す\r
1164 SOCKET SFTP_socket(int af, int type, int protocol)\r
1165 {\r
1166         SOCKET r;\r
1167         SFTPDATA* pSFTPData;\r
1168         if(!g_bPuTTYLoaded)\r
1169                 return INVALID_SOCKET;\r
1170         r = INVALID_SOCKET;\r
1171         EnterCriticalSection(&g_PuTTYLock);\r
1172         if(pSFTPData = GetUnusedSFTPData())\r
1173         {\r
1174                 r = socket(af, type, protocol);\r
1175                 pSFTPData->Control = r;\r
1176                 pSFTPData->Data = INVALID_SOCKET;\r
1177                 pSFTPData->Handle = p_SFTP_Create();\r
1178         }\r
1179         LeaveCriticalSection(&g_PuTTYLock);\r
1180         return r;\r
1181 }\r
1182 \r
1183 int SFTP_bind(SOCKET s, const struct sockaddr *addr, int namelen)\r
1184 {\r
1185         return SOCKET_ERROR;\r
1186 }\r
1187 \r
1188 int SFTP_listen(SOCKET s, int backlog)\r
1189 {\r
1190         return SOCKET_ERROR;\r
1191 }\r
1192 \r
1193 // accept相当の関数\r
1194 SOCKET SFTP_accept(SOCKET s, struct sockaddr *addr, int *addrlen)\r
1195 {\r
1196         return INVALID_SOCKET;\r
1197 }\r
1198 \r
1199 // connect相当の関数\r
1200 int SFTP_connect(SOCKET s, const struct sockaddr *name, int namelen)\r
1201 {\r
1202         SFTPDATA* pSFTPData;\r
1203         if(!g_bPuTTYLoaded)\r
1204                 return SOCKET_ERROR;\r
1205         EnterCriticalSection(&g_PuTTYLock);\r
1206         pSFTPData = FindSFTPDataFromSocket(s);\r
1207         LeaveCriticalSection(&g_PuTTYLock);\r
1208         if(!pSFTPData)\r
1209                 return SOCKET_ERROR;\r
1210         if(namelen == sizeof(struct sockaddr_in))\r
1211         {\r
1212         }\r
1213         else if(namelen == sizeof(struct sockaddr_in6))\r
1214         {\r
1215         }\r
1216         else\r
1217                 return SOCKET_ERROR;\r
1218         return 0;\r
1219 }\r
1220 \r
1221 // closesocket相当の関数\r
1222 int SFTP_closesocket(SOCKET s)\r
1223 {\r
1224         SFTPDATA* pSFTPData;\r
1225         if(!g_bPuTTYLoaded)\r
1226                 return SOCKET_ERROR;\r
1227         EnterCriticalSection(&g_PuTTYLock);\r
1228         if(pSFTPData = FindSFTPDataFromSocket(s))\r
1229         {\r
1230                 if(pSFTPData->Control == s)\r
1231                 {\r
1232                         pSFTPData->Control = INVALID_SOCKET;\r
1233                         p_SFTP_Destroy(pSFTPData->Handle);\r
1234                 }\r
1235                 if(pSFTPData->Data == s)\r
1236                         pSFTPData->Data = INVALID_SOCKET;\r
1237         }\r
1238         LeaveCriticalSection(&g_PuTTYLock);\r
1239         return closesocket(s);\r
1240 }\r
1241 \r
1242 // send相当の関数\r
1243 int SFTP_send(SOCKET s, const char * buf, int len, int flags)\r
1244 {\r
1245         int r;\r
1246         SFTPDATA* pSFTPData;\r
1247         if(!g_bPuTTYLoaded)\r
1248                 return SOCKET_ERROR;\r
1249         EnterCriticalSection(&g_PuTTYLock);\r
1250         pSFTPData = FindSFTPDataFromSocket(s);\r
1251         LeaveCriticalSection(&g_PuTTYLock);\r
1252         if(!pSFTPData)\r
1253                 return SOCKET_ERROR;\r
1254         if(p_SFTP_IsExited(pSFTPData->Handle))\r
1255                 return SOCKET_ERROR;\r
1256         r = SOCKET_ERROR;\r
1257         if(pSFTPData->Control == s)\r
1258                 r = (int)p_SFTP_WriteStdIn(pSFTPData->Handle, buf, len);\r
1259         else if(pSFTPData->Data == s)\r
1260                 r = (int)p_SFTP_WriteDataIn(pSFTPData->Handle, buf, len);\r
1261         return r;\r
1262 }\r
1263 \r
1264 // recv相当の関数\r
1265 int SFTP_recv(SOCKET s, char * buf, int len, int flags)\r
1266 {\r
1267         int r;\r
1268         SFTPDATA* pSFTPData;\r
1269         if(!g_bPuTTYLoaded)\r
1270                 return SOCKET_ERROR;\r
1271         EnterCriticalSection(&g_PuTTYLock);\r
1272         pSFTPData = FindSFTPDataFromSocket(s);\r
1273         LeaveCriticalSection(&g_PuTTYLock);\r
1274         if(!pSFTPData)\r
1275                 return SOCKET_ERROR;\r
1276         if(p_SFTP_IsExited(pSFTPData->Handle))\r
1277                 return SOCKET_ERROR;\r
1278         r = SOCKET_ERROR;\r
1279         if(pSFTPData->Control == s)\r
1280         {\r
1281                 if(flags & MSG_PEEK)\r
1282                         r = (int)p_SFTP_PeekStdOut(pSFTPData->Handle, buf, len);\r
1283                 else\r
1284                         r = (int)p_SFTP_ReadStdOut(pSFTPData->Handle, buf, len);\r
1285         }\r
1286         else if(pSFTPData->Data == s)\r
1287         {\r
1288                 if(flags & MSG_PEEK)\r
1289                         r = (int)p_SFTP_PeekDataOut(pSFTPData->Handle, buf, len);\r
1290                 else\r
1291                         r = (int)p_SFTP_ReadDataOut(pSFTPData->Handle, buf, len);\r
1292         }\r
1293         return r;\r
1294 }\r
1295 \r
1296 BOOL SFTP_SetTimeoutCallback(SOCKET s, void* pCallback)\r
1297 {\r
1298         SFTPDATA* pSFTPData;\r
1299         if(!g_bPuTTYLoaded)\r
1300                 return FALSE;\r
1301         EnterCriticalSection(&g_PuTTYLock);\r
1302         pSFTPData = FindSFTPDataFromSocket(s);\r
1303         LeaveCriticalSection(&g_PuTTYLock);\r
1304         if(!pSFTPData)\r
1305                 return FALSE;\r
1306         return p_SFTP_SetTimeoutCallback(pSFTPData->Handle, pCallback);\r
1307 }\r
1308 \r
1309 // データ用の仮想的なソケットを取得\r
1310 // 識別子としてダミーのソケットを返す\r
1311 SOCKET SFTP_GetDataHandle(SOCKET s, int af, int type, int protocol)\r
1312 {\r
1313         SOCKET r;\r
1314         SFTPDATA* pSFTPData;\r
1315         if(!g_bPuTTYLoaded)\r
1316                 return INVALID_SOCKET;\r
1317         r = INVALID_SOCKET;\r
1318         EnterCriticalSection(&g_PuTTYLock);\r
1319         if(pSFTPData = FindSFTPDataFromSocket(s))\r
1320         {\r
1321                 r = socket(af, type, protocol);\r
1322                 pSFTPData->Data = r;\r
1323         }\r
1324         LeaveCriticalSection(&g_PuTTYLock);\r
1325         return r;\r
1326 }\r
1327 \r
1328 BOOL SFTP_SetFilePosition(SOCKET s, LONGLONG Position)\r
1329 {\r
1330         SFTPDATA* pSFTPData;\r
1331         if(!g_bPuTTYLoaded)\r
1332                 return FALSE;\r
1333         EnterCriticalSection(&g_PuTTYLock);\r
1334         pSFTPData = FindSFTPDataFromSocket(s);\r
1335         LeaveCriticalSection(&g_PuTTYLock);\r
1336         if(!pSFTPData)\r
1337                 return FALSE;\r
1338         return p_SFTP_SetFilePosition(pSFTPData->Handle, Position);\r
1339 }\r
1340 \r