* copy vendor drop to trunk
[lab.git] / Dev / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Protocol.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // Protocol.c\r
79 // SoftEther プロトコル関係のルーチン\r
80 \r
81 #include "CedarPch.h"\r
82 \r
83 static char http_404_str[] = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>404 Not Found</TITLE>\r\n</HEAD><BODY>\r\n<H1>Not Found</H1>\r\nThe requested URL $TARGET$ was not found on this server.<P>\r\n<HR>\r\n<ADDRESS>HTTP Server at $HOST$ Port $PORT$</ADDRESS>\r\n</BODY></HTML>\r\n";\r
84 static char http_403_str[] = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>403 Forbidden</TITLE>\r\n</HEAD><BODY>\r\n<H1>Forbidden</H1>\r\nYou don't have permission to access $TARGET$\r\non this server.<P>\r\n<HR>\r\n<ADDRESS>HTTP Server at $HOST$ Port $PORT$</ADDRESS>\r\n</BODY></HTML>\r\n";\r
85 static char http_501_str[] = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\n<H1>Method Not Implemented</H1>\r\n$METHOD$ to $TARGET$ not supported.<P>\r\nInvalid method in request $METHOD$ $TARGET$ $VERSION$<P>\r\n<HR>\r\n<ADDRESS>HTTP Server at $HOST$ Port $PORT$</ADDRESS>\r\n</BODY></HTML>\r\n";\r
86 \r
87 // マシンごとにユニークな ID を生成する\r
88 void GenerateMachineUniqueHash(void *data)\r
89 {\r
90         BUF *b;\r
91         char name[64];\r
92         char ip_str[64];\r
93         IP ip;\r
94         OS_INFO *osinfo;\r
95         // 引数チェック\r
96         if (data == NULL)\r
97         {\r
98                 return;\r
99         }\r
100 \r
101         b = NewBuf();\r
102         GetMachineName(name, sizeof(name));\r
103         GetMachineIp(&ip);\r
104         IPToStr(ip_str, sizeof(ip_str), &ip);\r
105 \r
106         osinfo = GetOsInfo();\r
107 \r
108         WriteBuf(b, name, StrLen(name));\r
109         WriteBuf(b, ip_str, StrLen(ip_str));\r
110 \r
111         WriteBuf(b, &osinfo->OsType, sizeof(osinfo->OsType));\r
112         WriteBuf(b, osinfo->KernelName, StrLen(osinfo->KernelName));\r
113         WriteBuf(b, osinfo->KernelVersion, StrLen(osinfo->KernelVersion));\r
114         WriteBuf(b, osinfo->OsProductName, StrLen(osinfo->OsProductName));\r
115         WriteBuf(b, &osinfo->OsServicePack, sizeof(osinfo->OsServicePack));\r
116         WriteBuf(b, osinfo->OsSystemName, StrLen(osinfo->OsSystemName));\r
117         WriteBuf(b, osinfo->OsVendorName, StrLen(osinfo->OsVendorName));\r
118         WriteBuf(b, osinfo->OsVersion, StrLen(osinfo->OsVersion));\r
119 \r
120         Hash(data, b->Buf, b->Size, true);\r
121 \r
122         FreeBuf(b);\r
123 }\r
124 \r
125 // ノード情報を文字列に変換する\r
126 void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info)\r
127 {\r
128         char client_ip[128], server_ip[128], proxy_ip[128], unique_id[128];\r
129         // 引数チェック\r
130         if (str == NULL || info == NULL)\r
131         {\r
132                 return;\r
133         }\r
134 \r
135         IPToStr4or6(client_ip, sizeof(client_ip), info->ClientIpAddress, info->ClientIpAddress6);\r
136         IPToStr4or6(server_ip, sizeof(server_ip), info->ServerIpAddress, info->ServerIpAddress6);\r
137         IPToStr4or6(proxy_ip, sizeof(proxy_ip), info->ProxyIpAddress, info->ProxyIpAddress6);\r
138         BinToStr(unique_id, sizeof(unique_id), info->UniqueId, sizeof(info->UniqueId));\r
139 \r
140         UniFormat(str, size, _UU("LS_NODE_INFO_TAG"), info->ClientProductName,\r
141                 Endian32(info->ClientProductVer), Endian32(info->ClientProductBuild),\r
142                 info->ServerProductName, Endian32(info->ServerProductVer), Endian32(info->ServerProductBuild),\r
143                 info->ClientOsName, info->ClientOsVer, info->ClientOsProductId,\r
144                 info->ClientHostname, client_ip, Endian32(info->ClientPort),\r
145                 info->ServerHostname, server_ip, Endian32(info->ServerPort),\r
146                 info->ProxyHostname, proxy_ip, Endian32(info->ProxyPort),\r
147                 info->HubName, unique_id);\r
148 }\r
149 \r
150 // ノード情報の比較\r
151 bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b)\r
152 {\r
153         // 引数チェック\r
154         if (a == NULL || b == NULL)\r
155         {\r
156                 return false;\r
157         }\r
158 \r
159         // このあたりは急いで実装したのでコードがあまり美しくない。\r
160         if (StrCmp(a->ClientProductName, b->ClientProductName) != 0)\r
161         {\r
162                 return false;\r
163         }\r
164         if (a->ClientProductVer != b->ClientProductVer)\r
165         {\r
166                 return false;\r
167         }\r
168         if (a->ClientProductBuild != b->ClientProductBuild)\r
169         {\r
170                 return false;\r
171         }\r
172         if (StrCmp(a->ServerProductName, b->ServerProductName) != 0)\r
173         {\r
174                 return false;\r
175         }\r
176         if (a->ServerProductVer != b->ServerProductVer)\r
177         {\r
178                 return false;\r
179         }\r
180         if (a->ServerProductBuild != b->ServerProductBuild)\r
181         {\r
182                 return false;\r
183         }\r
184         if (StrCmp(a->ClientOsName, b->ClientOsName) != 0)\r
185         {\r
186                 return false;\r
187         }\r
188         if (StrCmp(a->ClientOsVer, b->ClientOsVer) != 0)\r
189         {\r
190                 return false;\r
191         }\r
192         if (StrCmp(a->ClientOsProductId, b->ClientOsProductId) != 0)\r
193         {\r
194                 return false;\r
195         }\r
196         if (StrCmp(a->ClientHostname, b->ClientHostname) != 0)\r
197         {\r
198                 return false;\r
199         }\r
200         if (a->ClientIpAddress != b->ClientIpAddress)\r
201         {\r
202                 return false;\r
203         }\r
204         if (StrCmp(a->ServerHostname, b->ServerHostname) != 0)\r
205         {\r
206                 return false;\r
207         }\r
208         if (a->ServerIpAddress != b->ServerIpAddress)\r
209         {\r
210                 return false;\r
211         }\r
212         if (a->ServerPort != b->ServerPort)\r
213         {\r
214                 return false;\r
215         }\r
216         if (StrCmp(a->ProxyHostname, b->ProxyHostname) != 0)\r
217         {\r
218                 return false;\r
219         }\r
220         if (a->ProxyIpAddress != b->ProxyIpAddress)\r
221         {\r
222                 return false;\r
223         }\r
224         if (a->ProxyPort != b->ProxyPort)\r
225         {\r
226                 return false;\r
227         }\r
228         if (StrCmp(a->HubName, b->HubName) != 0)\r
229         {\r
230                 return false;\r
231         }\r
232         if (Cmp(a->UniqueId, b->UniqueId, 16) != 0)\r
233         {\r
234                 return false;\r
235         }\r
236 \r
237         return true;\r
238 }\r
239 \r
240 // パスワード変更受付\r
241 UINT ChangePasswordAccept(CONNECTION *c, PACK *p)\r
242 {\r
243         CEDAR *cedar;\r
244         UCHAR random[SHA1_SIZE];\r
245         char hubname[MAX_HUBNAME_LEN + 1];\r
246         char username[MAX_USERNAME_LEN + 1];\r
247         UCHAR secure_old_password[SHA1_SIZE];\r
248         UCHAR new_password[SHA1_SIZE];\r
249         UCHAR check_secure_old_password[SHA1_SIZE];\r
250         UINT ret = ERR_NO_ERROR;\r
251         HUB *hub;\r
252         bool save = false;\r
253         // 引数チェック\r
254         if (c == NULL || p == NULL)\r
255         {\r
256                 return ERR_INTERNAL_ERROR;\r
257         }\r
258 \r
259         Copy(random, c->Random, SHA1_SIZE);\r
260         if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false ||\r
261                 PackGetStr(p, "username", username, sizeof(username)) == false ||\r
262                 PackGetData2(p, "secure_old_password", secure_old_password, sizeof(secure_old_password)) == false ||\r
263                 PackGetData2(p, "new_password", new_password, sizeof(new_password)) == false)\r
264         {\r
265                 return ERR_PROTOCOL_ERROR;\r
266         }\r
267 \r
268         cedar = c->Cedar;\r
269 \r
270         LockHubList(cedar);\r
271         {\r
272                 hub = GetHub(cedar, hubname);\r
273         }\r
274         UnlockHubList(cedar);\r
275 \r
276         if (hub == NULL)\r
277         {\r
278                 ret = ERR_HUB_NOT_FOUND;\r
279         }\r
280         else\r
281         {\r
282                 char tmp[MAX_SIZE];\r
283 \r
284                 if (GetHubAdminOption(hub, "deny_change_user_password") != 0)\r
285                 {\r
286                         ReleaseHub(hub);\r
287                         return ERR_NOT_ENOUGH_RIGHT;\r
288                 }\r
289 \r
290                 IPToStr(tmp, sizeof(tmp), &c->FirstSock->RemoteIP);\r
291                 HLog(hub, "LH_CHANGE_PASSWORD_1", c->Name, tmp);\r
292 \r
293                 AcLock(hub);\r
294                 {\r
295                         USER *u = AcGetUser(hub, username);\r
296                         if (u == NULL)\r
297                         {\r
298                                 HLog(hub, "LH_CHANGE_PASSWORD_2", c->Name, username);\r
299                                 ret = ERR_OLD_PASSWORD_WRONG;\r
300                         }\r
301                         else\r
302                         {\r
303                                 Lock(u->lock);\r
304                                 {\r
305                                         if (u->AuthType != AUTHTYPE_PASSWORD)\r
306                                         {\r
307                                                 // パスワード認証ではない\r
308                                                 HLog(hub, "LH_CHANGE_PASSWORD_3", c->Name, username);\r
309                                                 ret = ERR_USER_AUTHTYPE_NOT_PASSWORD;\r
310                                         }\r
311                                         else\r
312                                         {\r
313                                                 bool fix_password = false;\r
314                                                 if (u->Policy != NULL)\r
315                                                 {\r
316                                                         fix_password = u->Policy->FixPassword;\r
317                                                 }\r
318                                                 else\r
319                                                 {\r
320                                                         if (u->Group != NULL)\r
321                                                         {\r
322                                                                 if (u->Group->Policy != NULL)\r
323                                                                 {\r
324                                                                         fix_password = u->Group->Policy->FixPassword;\r
325                                                                 }\r
326                                                         }\r
327                                                 }\r
328                                                 if (fix_password == false)\r
329                                                 {\r
330                                                         // 古いパスワードの確認\r
331                                                         AUTHPASSWORD *pw = (AUTHPASSWORD *)u->AuthData;\r
332 \r
333                                                         SecurePassword(check_secure_old_password, pw->HashedKey, random);\r
334                                                         if (Cmp(check_secure_old_password, secure_old_password, SHA1_SIZE) != 0)\r
335                                                         {\r
336                                                                 // 古いパスワードが間違っている\r
337                                                                 ret = ERR_OLD_PASSWORD_WRONG;\r
338                                                                 HLog(hub, "LH_CHANGE_PASSWORD_4", c->Name, username);\r
339                                                         }\r
340                                                         else\r
341                                                         {\r
342                                                                 // 新しいパスワードの書き込み\r
343                                                                 Copy(pw->HashedKey, new_password, SHA1_SIZE);\r
344                                                                 HLog(hub, "LH_CHANGE_PASSWORD_5", c->Name, username);\r
345                                                                 save = true;\r
346                                                         }\r
347                                                 }\r
348                                                 else\r
349                                                 {\r
350                                                         // パスワード変更は禁止\r
351                                                         ret = ERR_NOT_ENOUGH_RIGHT;\r
352                                                 }\r
353                                         }\r
354                                 }\r
355                                 Unlock(u->lock);\r
356 \r
357                                 ReleaseUser(u);\r
358                         }\r
359                 }\r
360                 AcUnlock(hub);\r
361                 ReleaseHub(hub);\r
362         }\r
363 \r
364         return ret;\r
365 }\r
366 \r
367 // パスワードを変更する\r
368 UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass)\r
369 {\r
370         UINT ret = ERR_NO_ERROR;\r
371         UCHAR old_password[SHA1_SIZE];\r
372         UCHAR secure_old_password[SHA1_SIZE];\r
373         UCHAR new_password[SHA1_SIZE];\r
374         SOCK *sock;\r
375         SESSION *s;\r
376         // 引数チェック\r
377         if (cedar == NULL || o == NULL || hubname == NULL || username == NULL || old_pass == NULL || new_pass == NULL)\r
378         {\r
379                 return ERR_INTERNAL_ERROR;\r
380         }\r
381 \r
382 \r
383         // セッション作成\r
384         s = NewRpcSessionEx(cedar, o, &ret, NULL);\r
385 \r
386         if (s != NULL)\r
387         {\r
388                 PACK *p = NewPack();\r
389 \r
390                 sock = s->Connection->FirstSock;\r
391 \r
392                 HashPassword(old_password, username, old_pass);\r
393                 SecurePassword(secure_old_password, old_password, s->Connection->Random);\r
394                 HashPassword(new_password, username, new_pass);\r
395 \r
396                 PackAddClientVersion(p, s->Connection);\r
397 \r
398                 PackAddStr(p, "method", "password");\r
399                 PackAddStr(p, "hubname", hubname);\r
400                 PackAddStr(p, "username", username);\r
401                 PackAddData(p, "secure_old_password", secure_old_password, SHA1_SIZE);\r
402                 PackAddData(p, "new_password", new_password, SHA1_SIZE);\r
403 \r
404                 if (HttpClientSend(sock, p))\r
405                 {\r
406                         PACK *p = HttpClientRecv(sock);\r
407                         if (p == NULL)\r
408                         {\r
409                                 ret = ERR_DISCONNECTED;\r
410                         }\r
411                         else\r
412                         {\r
413                                 ret = GetErrorFromPack(p);\r
414                         }\r
415                         FreePack(p);\r
416                 }\r
417                 else\r
418                 {\r
419                         ret = ERR_DISCONNECTED;\r
420                 }\r
421                 FreePack(p);\r
422 \r
423                 ReleaseSession(s);\r
424         }\r
425 \r
426         return ret;\r
427 }\r
428 \r
429 // HUB を列挙する\r
430 TOKEN_LIST *EnumHub(SESSION *s)\r
431 {\r
432         SOCK *sock;\r
433         TOKEN_LIST *ret;\r
434         PACK *p;\r
435         UINT num;\r
436         UINT i;\r
437         // 引数チェック\r
438         if (s == NULL || s->Connection == NULL)\r
439         {\r
440                 return NULL;\r
441         }\r
442 \r
443         sock = s->Connection->FirstSock;\r
444         if (sock == NULL)\r
445         {\r
446                 return NULL;\r
447         }\r
448 \r
449         // タイムアウトの設定\r
450         SetTimeout(sock, 10000);\r
451 \r
452         p = NewPack();\r
453         PackAddStr(p, "method", "enum_hub");\r
454 \r
455         PackAddClientVersion(p, s->Connection);\r
456 \r
457         if (HttpClientSend(sock, p) == false)\r
458         {\r
459                 FreePack(p);\r
460                 return NULL;\r
461         }\r
462         FreePack(p);\r
463 \r
464         p = HttpClientRecv(sock);\r
465         if (p == NULL)\r
466         {\r
467                 return NULL;\r
468         }\r
469 \r
470         num = PackGetInt(p, "NumHub");\r
471         ret = ZeroMalloc(sizeof(TOKEN_LIST));\r
472         ret->NumTokens = num;\r
473         ret->Token = ZeroMalloc(sizeof(char *) * num);\r
474         for (i = 0;i < num;i++)\r
475         {\r
476                 char tmp[MAX_SIZE];\r
477                 if (PackGetStrEx(p, "HubName", tmp, sizeof(tmp), i))\r
478                 {\r
479                         ret->Token[i] = CopyStr(tmp);\r
480                 }\r
481         }\r
482         FreePack(p);\r
483 \r
484         return ret;\r
485 }\r
486 \r
487 // サーバーがクライアントからの接続を受け付ける\r
488 bool ServerAccept(CONNECTION *c)\r
489 {\r
490         bool ret = false;\r
491         UINT err;\r
492         PACK *p;\r
493         char username_real[MAX_SIZE];\r
494         char method[MAX_SIZE];\r
495         char hubname[MAX_SIZE];\r
496         char username[MAX_SIZE];\r
497         char groupname[MAX_SIZE];\r
498         UCHAR session_key[SHA1_SIZE];\r
499         UCHAR ticket[SHA1_SIZE];\r
500         RC4_KEY_PAIR key_pair;\r
501         UINT authtype;\r
502         POLICY *policy;\r
503         HUB *hub;\r
504         SESSION *s;\r
505         UINT64 user_expires = 0;\r
506         bool use_encrypt;\r
507         bool use_compress;\r
508         bool half_connection;\r
509         bool use_fast_rc4;\r
510         bool admin_mode = false;\r
511         UINT direction;\r
512         UINT max_connection;\r
513         UINT timeout;\r
514         bool farm_controller = false;\r
515         bool farm_member = false;\r
516         bool farm_mode = false;\r
517         bool require_bridge_routing_mode;\r
518         bool require_monitor_mode;\r
519         bool use_client_license = false, use_bridge_license = false;\r
520         bool local_host_session = false;\r
521         char sessionname[MAX_SESSION_NAME_LEN + 1];\r
522         bool is_server_or_bridge = false;\r
523         bool qos = false;\r
524         bool cluster_dynamic_secure_nat = false;\r
525         bool no_save_password = false;\r
526         NODE_INFO node;\r
527         wchar_t *msg = NULL;\r
528         USER *loggedin_user_object = NULL;\r
529         FARM_MEMBER *f = NULL;\r
530         SERVER *server = NULL;\r
531         POLICY ticketed_policy;\r
532         UINT64 timestamp;\r
533         UCHAR unique[SHA1_SIZE], unique2[SHA1_SIZE];\r
534         LICENSE_STATUS license;\r
535         CEDAR *cedar;\r
536         RPC_WINVER winver;\r
537         UINT client_id;\r
538         bool no_more_users_in_server = false;\r
539 \r
540         // 引数チェック\r
541         if (c == NULL)\r
542         {\r
543                 return false;\r
544         }\r
545 \r
546         Zero(&winver, sizeof(winver));\r
547 \r
548         StrCpy(groupname, sizeof(groupname), "");\r
549         StrCpy(sessionname, sizeof(sessionname), "");\r
550 \r
551         cedar = c->Cedar;\r
552 \r
553         // ライセンス状況の取得\r
554         Zero(&license, sizeof(license));\r
555         if (c->Cedar->Server != NULL)\r
556         {\r
557                 LiParseCurrentLicenseStatus(c->Cedar->Server->LicenseSystem, &license);\r
558         }\r
559 \r
560         no_more_users_in_server = SiTooManyUserObjectsInServer(cedar->Server, true);\r
561 \r
562         c->Status = CONNECTION_STATUS_NEGOTIATION;\r
563 \r
564         if (c->Cedar->Server != NULL)\r
565         {\r
566                 SERVER *s = c->Cedar->Server;\r
567                 server = s;\r
568 \r
569                 if (s->ServerType == SERVER_TYPE_FARM_MEMBER)\r
570                 {\r
571                         farm_member = true;\r
572                         farm_mode = true;\r
573                 }\r
574 \r
575                 if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
576                 {\r
577                         farm_controller = true;\r
578                         farm_mode = true;\r
579                 }\r
580         }\r
581 \r
582         // シグネチャを受信\r
583         Debug("Downloading Signature...\n");\r
584         if (ServerDownloadSignature(c) == false)\r
585         {\r
586                 goto CLEANUP;\r
587         }\r
588 \r
589         // Hello パケットを送信\r
590         Debug("Uploading Hello...\n");\r
591         if (ServerUploadHello(c) == false)\r
592         {\r
593                 goto CLEANUP;\r
594         }\r
595 \r
596         // 認証データを受信\r
597         Debug("Auth...\n");\r
598 \r
599         p = HttpServerRecv(c->FirstSock);\r
600         if (p == NULL)\r
601         {\r
602                 // 通信切断\r
603                 c->Err = ERR_DISCONNECTED;\r
604                 goto CLEANUP;\r
605         }\r
606 \r
607         if (err = GetErrorFromPack(p))\r
608         {\r
609                 // エラー発生\r
610                 FreePack(p);\r
611                 c->Err = err;\r
612                 goto CLEANUP;\r
613         }\r
614 \r
615         // メソッド取得\r
616         if (GetMethodFromPack(p, method, sizeof(method)) == false)\r
617         {\r
618                 // プロトコルエラー\r
619                 FreePack(p);\r
620                 c->Err = ERR_PROTOCOL_ERROR;\r
621                 goto CLEANUP;\r
622         }\r
623 \r
624         // 時刻検査\r
625         timestamp = PackGetInt64(p, "timestamp");\r
626         if (timestamp != 0)\r
627         {\r
628                 UINT64 now = SystemTime64();\r
629                 UINT64 abs;\r
630                 if (now >= timestamp)\r
631                 {\r
632                         abs = now - timestamp;\r
633                 }\r
634                 else\r
635                 {\r
636                         abs = timestamp - now;\r
637                 }\r
638 \r
639                 if (abs > ALLOW_TIMESTAMP_DIFF)\r
640                 {\r
641                         // 時差が大きすぎる\r
642                         FreePack(p);\r
643                         c->Err = ERR_BAD_CLOCK;\r
644                         goto CLEANUP;\r
645                 }\r
646         }\r
647 \r
648         // クライアントバージョン取得\r
649         PackGetStr(p, "client_str", c->ClientStr, sizeof(c->ClientStr));\r
650         c->ClientVer = PackGetInt(p, "client_ver");\r
651         c->ClientBuild = PackGetInt(p, "client_build");\r
652 \r
653         if (SearchStrEx(c->ClientStr, "server", 0, false) != INFINITE ||\r
654                 SearchStrEx(c->ClientStr, "bridge", 0, false) != INFINITE)\r
655         {\r
656                 is_server_or_bridge = true;\r
657         }\r
658 \r
659         // クライアント Windows バージョンの取得\r
660         InRpcWinVer(&winver, p);\r
661 \r
662         DecrementNoSsl(c->Cedar, &c->FirstSock->RemoteIP, 2);\r
663 \r
664         if (StrCmpi(method, "login") == 0)\r
665         {\r
666                 bool auth_ret = false;\r
667 \r
668                 Debug("Login...\n");\r
669                 c->Status = CONNECTION_STATUS_USERAUTH;\r
670 \r
671                 c->Type = CONNECTION_TYPE_LOGIN;\r
672 \r
673                 if (no_more_users_in_server)\r
674                 {\r
675                         // VPN Server に許可されているよりも多くのユーザーが存在する\r
676                         FreePack(p);\r
677                         c->Err = ERR_TOO_MANY_USER;\r
678                         goto CLEANUP;\r
679                 }\r
680 \r
681                 // クライアント名など\r
682                 if (PackGetStr(p, "hello", c->ClientStr, sizeof(c->ClientStr)) == false)\r
683                 {\r
684                         StrCpy(c->ClientStr, sizeof(c->ClientStr), "Unknown");\r
685                 }\r
686                 c->ServerVer = CEDAR_VER;\r
687                 c->ServerBuild = CEDAR_BUILD;\r
688 \r
689                 // NODE_INFO を取得する\r
690                 Zero(&node, sizeof(node));\r
691                 InRpcNodeInfo(&node, p);\r
692 \r
693                 // プロトコル\r
694                 c->Protocol = GetProtocolFromPack(p);\r
695                 if (c->Protocol == CONNECTION_UDP)\r
696                 {\r
697                         // TCP 関係の構造体を解放する\r
698                         if (c->Tcp)\r
699                         {\r
700                                 ReleaseList(c->Tcp->TcpSockList);\r
701                                 Free(c->Tcp);\r
702                         }\r
703                 }\r
704 \r
705                 if (GetServerCapsBool(c->Cedar->Server, "b_vpn_client_connect") == false)\r
706                 {\r
707                         // VPN クライアントが接続不可能である\r
708                         FreePack(p);\r
709                         c->Err = ERR_NOT_SUPPORTED;\r
710                         goto CLEANUP;\r
711                 }\r
712 \r
713                 // ログイン\r
714                 if (GetHubnameAndUsernameFromPack(p, username, sizeof(username), hubname, sizeof(hubname)) == false)\r
715                 {\r
716                         // プロトコルエラー\r
717                         FreePack(p);\r
718                         c->Err = ERR_PROTOCOL_ERROR;\r
719                         goto CLEANUP;\r
720                 }\r
721 \r
722                 if (farm_member)\r
723                 {\r
724                         bool ok = false;\r
725                         UINT authtype;\r
726 \r
727                         authtype = GetAuthTypeFromPack(p);\r
728                         if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 &&\r
729                                 authtype == AUTHTYPE_PASSWORD)\r
730                         {\r
731                                 ok = true;\r
732                         }\r
733 \r
734                         if (authtype == AUTHTYPE_TICKET)\r
735                         {\r
736                                 ok = true;\r
737                         }\r
738 \r
739                         if (ok == false)\r
740                         {\r
741                                 // サーバーファームメンバへの Administrators 以外の直接ログオンは\r
742                                 // 禁止されている\r
743                                 FreePack(p);\r
744                                 SLog(c->Cedar, "LS_FARMMEMBER_NOT_ADMIN", c->Name, hubname, ADMINISTRATOR_USERNAME, username);\r
745                                 c->Err = ERR_ACCESS_DENIED;\r
746                                 goto CLEANUP;\r
747                         }\r
748                 }\r
749 \r
750                 Debug("Username = %s, HubName = %s\n", username, hubname);\r
751                 LockHubList(c->Cedar);\r
752                 {\r
753                         hub = GetHub(c->Cedar, hubname);\r
754                 }\r
755                 UnlockHubList(c->Cedar);\r
756                 if (hub == NULL)\r
757                 {\r
758                         // HUB が存在しない\r
759                         FreePack(p);\r
760                         c->Err = ERR_HUB_NOT_FOUND;\r
761                         SLog(c->Cedar, "LS_HUB_NOT_FOUND", c->Name, hubname);\r
762                         goto CLEANUP;\r
763                 }\r
764 \r
765                 Lock(hub->lock);\r
766                 {\r
767                         USER *user;\r
768                         USERGROUP *group;\r
769                         if (hub->Halt || hub->Offline)\r
770                         {\r
771                                 // HUB は停止中\r
772                                 FreePack(p);\r
773                                 Unlock(hub->lock);\r
774                                 ReleaseHub(hub);\r
775                                 c->Err = ERR_HUB_STOPPING;\r
776                                 goto CLEANUP;\r
777                         }\r
778 \r
779                         // 各種フラグの取得\r
780                         use_encrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;\r
781                         use_compress = PackGetInt(p, "use_compress") == 0 ? false : true;\r
782                         max_connection = PackGetInt(p, "max_connection");\r
783                         half_connection = PackGetInt(p, "half_connection") == 0 ? false : true;\r
784                         use_fast_rc4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;\r
785                         qos = PackGetInt(p, "qos") ? true : false;\r
786                         client_id = PackGetInt(p, "client_id");\r
787 \r
788                         // 要求モード\r
789                         require_bridge_routing_mode = PackGetBool(p, "require_bridge_routing_mode");\r
790                         require_monitor_mode = PackGetBool(p, "require_monitor_mode");\r
791                         if (require_monitor_mode)\r
792                         {\r
793                                 qos = false;\r
794                         }\r
795 \r
796                         if (is_server_or_bridge)\r
797                         {\r
798                                 require_bridge_routing_mode = true;\r
799                         }\r
800 \r
801                         // クライアントユニーク ID\r
802                         Zero(unique, sizeof(unique));\r
803                         if (PackGetDataSize(p, "unique_id") == SHA1_SIZE)\r
804                         {\r
805                                 PackGetData(p, "unique_id", unique);\r
806                         }\r
807 \r
808                         // 認証方法の取得\r
809                         authtype = GetAuthTypeFromPack(p);\r
810 \r
811                         if (1)\r
812                         {\r
813                                 // ログ\r
814                                 char ip1[64], ip2[64], verstr[64];\r
815                                 wchar_t *authtype_str = _UU("LH_AUTH_UNKNOWN");\r
816                                 switch (authtype)\r
817                                 {\r
818                                 case CLIENT_AUTHTYPE_ANONYMOUS:\r
819                                         authtype_str = _UU("LH_AUTH_ANONYMOUS");\r
820                                         break;\r
821                                 case CLIENT_AUTHTYPE_PASSWORD:\r
822                                         authtype_str = _UU("LH_AUTH_PASSWORD");\r
823                                         break;\r
824                                 case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
825                                         authtype_str = _UU("LH_AUTH_PLAIN_PASSWORD");\r
826                                         break;\r
827                                 case CLIENT_AUTHTYPE_CERT:\r
828                                         authtype_str = _UU("LH_AUTH_CERT");\r
829                                         break;\r
830                                 case AUTHTYPE_TICKET:\r
831                                         authtype_str = _UU("LH_AUTH_TICKET");\r
832                                         break;\r
833                                 }\r
834                                 IPToStr(ip1, sizeof(ip1), &c->FirstSock->RemoteIP);\r
835                                 IPToStr(ip2, sizeof(ip2), &c->FirstSock->LocalIP);\r
836 \r
837                                 Format(verstr, sizeof(verstr), "%u.%02u", c->ClientVer / 100, c->ClientVer % 100);\r
838 \r
839                                 HLog(hub, "LH_CONNECT_CLIENT", c->Name, ip1, c->FirstSock->RemoteHostname, c->FirstSock->RemotePort,\r
840                                         c->ClientStr, verstr, c->ClientBuild, authtype_str, username);\r
841                         }\r
842 \r
843                         // まず匿名認証を試行する\r
844                         auth_ret = SamAuthUserByAnonymous(hub, username);\r
845 \r
846                         if (auth_ret)\r
847                         {\r
848                                 // ユーザー認証成功\r
849                                 HLog(hub, "LH_AUTH_OK", c->Name, username);\r
850                         }\r
851 \r
852                         if (auth_ret == false)\r
853                         {\r
854                                 // 匿名認証に失敗した場合は他の認証方法を試行する\r
855                                 switch (authtype)\r
856                                 {\r
857                                 case CLIENT_AUTHTYPE_ANONYMOUS:\r
858                                         // 匿名認証 (すでに試行している)\r
859                                         break;\r
860 \r
861                                 case AUTHTYPE_TICKET:\r
862                                         // チケット認証\r
863                                         if (PackGetDataSize(p, "ticket") == SHA1_SIZE)\r
864                                         {\r
865                                                 PackGetData(p, "ticket", ticket);\r
866 \r
867                                                 auth_ret = SiCheckTicket(hub, ticket, username, sizeof(username), username_real, sizeof(username_real),\r
868                                                         &ticketed_policy, sessionname, sizeof(sessionname), groupname, sizeof(groupname));\r
869                                         }\r
870                                         break;\r
871 \r
872                                 case CLIENT_AUTHTYPE_PASSWORD:\r
873                                         // パスワード認証\r
874                                         if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)\r
875                                         {\r
876                                                 POLICY *pol = NULL;\r
877                                                 UCHAR secure_password[SHA1_SIZE];\r
878                                                 Zero(secure_password, sizeof(secure_password));\r
879                                                 if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)\r
880                                                 {\r
881                                                         PackGetData(p, "secure_password", secure_password);\r
882                                                 }\r
883                                                 auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password);\r
884 \r
885                                                 pol = SamGetUserPolicy(hub, username);\r
886                                                 if (pol != NULL)\r
887                                                 {\r
888                                                         no_save_password = pol->NoSavePassword;\r
889                                                         Free(pol);\r
890                                                 }\r
891                                         }\r
892                                         break;\r
893 \r
894                                 case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
895                                         // 外部サーバーによる認証はサポートされていない\r
896                                         HLog(hub, "LH_AUTH_RADIUS_NOT_SUPPORT", c->Name, username);\r
897                                         Unlock(hub->lock);\r
898                                         ReleaseHub(hub);\r
899                                         FreePack(p);\r
900                                         c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;\r
901                                         goto CLEANUP;\r
902 \r
903                                 case CLIENT_AUTHTYPE_CERT:\r
904                                         // 証明書認証はサポートされていない\r
905                                         HLog(hub, "LH_AUTH_CERT_NOT_SUPPORT", c->Name, username);\r
906                                         Unlock(hub->lock);\r
907                                         ReleaseHub(hub);\r
908                                         FreePack(p);\r
909                                         c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;\r
910                                         goto CLEANUP;\r
911 \r
912                                 default:\r
913                                         // 不明な認証方法\r
914                                         Unlock(hub->lock);\r
915                                         ReleaseHub(hub);\r
916                                         FreePack(p);\r
917                                         c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;\r
918                                         goto CLEANUP;\r
919                                 }\r
920 \r
921                                 if (auth_ret == false)\r
922                                 {\r
923                                         // 認証失敗\r
924                                         HLog(hub, "LH_AUTH_NG", c->Name, username);\r
925                                 }\r
926                                 else\r
927                                 {\r
928                                         // 認証成功\r
929                                         HLog(hub, "LH_AUTH_OK", c->Name, username);\r
930                                 }\r
931                         }\r
932 \r
933                         if (auth_ret == false)\r
934                         {\r
935                                 // 認証失敗\r
936                                 Unlock(hub->lock);\r
937                                 ReleaseHub(hub);\r
938                                 FreePack(p);\r
939                                 c->Err = ERR_AUTH_FAILED;\r
940                                 goto CLEANUP;\r
941                         }\r
942                         else\r
943                         {\r
944                                 if (authtype == CLIENT_AUTHTYPE_PASSWORD)\r
945                                 {\r
946                                         UCHAR test[SHA1_SIZE];\r
947                                         HashPassword(test, username, "");\r
948                                         if (Cmp(test, hub->SecurePassword, SHA1_SIZE) == 0)\r
949                                         {\r
950                                                 SOCK *s = c->FirstSock;\r
951                                                 if (s != NULL)\r
952                                                 {\r
953                                                         if (GetHubAdminOption(hub, "deny_empty_password") != 0 ||\r
954                                                                 (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 && s->RemoteIP.addr[0] != 127))\r
955                                                         {\r
956                                                                 // パスワードが空のとき、リモートから接続してはいけない\r
957                                                                 HLog(hub, "LH_LOCAL_ONLY", c->Name, username);\r
958 \r
959                                                                 Unlock(hub->lock);\r
960                                                                 ReleaseHub(hub);\r
961                                                                 FreePack(p);\r
962                                                                 c->Err = ERR_NULL_PASSWORD_LOCAL_ONLY;\r
963                                                                 goto CLEANUP;\r
964                                                         }\r
965                                                 }\r
966                                         }\r
967                                 }\r
968                         }\r
969 \r
970                         policy = NULL;\r
971 \r
972                         // 認証成功\r
973                         FreePack(p);\r
974 \r
975                         if (StrCmpi(username, ADMINISTRATOR_USERNAME) != 0)\r
976                         {\r
977                                 // ポリシーを取得\r
978                                 if (farm_member == false)\r
979                                 {\r
980                                         // ファームメンバ以外の場合\r
981                                         user = AcGetUser(hub, username);\r
982                                         if (user == NULL)\r
983                                         {\r
984                                                 user = AcGetUser(hub, "*");\r
985                                                 if (user == NULL)\r
986                                                 {\r
987                                                         // ユーザー取得失敗\r
988                                                         Unlock(hub->lock);\r
989                                                         ReleaseHub(hub);\r
990                                                         c->Err = ERR_ACCESS_DENIED;\r
991                                                         goto CLEANUP;\r
992                                                 }\r
993                                         }\r
994 \r
995                                         policy = NULL;\r
996 \r
997                                         Lock(user->lock);\r
998                                         {\r
999                                                 // 有効期限を取得\r
1000                                                 user_expires = user->ExpireTime;\r
1001 \r
1002                                                 StrCpy(username_real, sizeof(username_real), user->Name);\r
1003                                                 group = user->Group;\r
1004                                                 if (group != NULL)\r
1005                                                 {\r
1006                                                         AddRef(group->ref);\r
1007 \r
1008                                                         Lock(group->lock);\r
1009                                                         {\r
1010                                                                 // グループ名を取得\r
1011                                                                 StrCpy(groupname, sizeof(groupname), group->Name);\r
1012                                                         }\r
1013                                                         Unlock(group->lock);\r
1014                                                 }\r
1015 \r
1016                                                 if (user->Policy != NULL)\r
1017                                                 {\r
1018                                                         policy = ClonePolicy(user->Policy);\r
1019                                                 }\r
1020                                                 else\r
1021                                                 {\r
1022                                                         if (group)\r
1023                                                         {\r
1024                                                                 Lock(group->lock);\r
1025                                                                 {\r
1026                                                                         if (group->Policy != NULL)\r
1027                                                                         {\r
1028                                                                                 policy = ClonePolicy(group->Policy);\r
1029                                                                         }\r
1030                                                                 }\r
1031                                                                 Unlock(group->lock);\r
1032                                                         }\r
1033                                                 }\r
1034 \r
1035                                                 if (group != NULL)\r
1036                                                 {\r
1037                                                         ReleaseGroup(group);\r
1038                                                 }\r
1039                                         }\r
1040                                         Unlock(user->lock);\r
1041                                         loggedin_user_object = user;\r
1042                                 }\r
1043                                 else\r
1044                                 {\r
1045                                         // ファームメンバの場合\r
1046                                         policy = ClonePolicy(&ticketed_policy);\r
1047                                 }\r
1048                         }\r
1049                         else\r
1050                         {\r
1051                                 // 管理者モード\r
1052                                 admin_mode = true;\r
1053                                 StrCpy(username_real, sizeof(username_real), ADMINISTRATOR_USERNAME);\r
1054 \r
1055                                 policy = ClonePolicy(GetDefaultPolicy());\r
1056                                 policy->NoBroadcastLimiter = true;\r
1057                                 policy->MonitorPort = true;\r
1058                         }\r
1059 \r
1060                         if (policy == NULL)\r
1061                         {\r
1062                                 // デフォルトのポリシーを使用する\r
1063                                 policy = ClonePolicy(GetDefaultPolicy());\r
1064                         }\r
1065 \r
1066                         if (policy->MaxConnection == 0)\r
1067                         {\r
1068                                 policy->MaxConnection = MAX_TCP_CONNECTION;\r
1069                         }\r
1070 \r
1071                         if (policy->TimeOut == 0)\r
1072                         {\r
1073                                 policy->TimeOut = 20;\r
1074                         }\r
1075 \r
1076                         if (qos)\r
1077                         {\r
1078                                 // VoIP / QoS\r
1079                                 if (policy->NoQoS)\r
1080                                 {\r
1081                                         // ポリシーが許可していない\r
1082                                         qos = false;\r
1083                                 }\r
1084                                 if (GetServerCapsBool(c->Cedar->Server, "b_support_qos") == false)\r
1085                                 {\r
1086                                         // サーバーがサポートしていない\r
1087                                         qos = false;\r
1088                                         policy->NoQoS = true;\r
1089                                 }\r
1090                                 if (GetHubAdminOption(hub, "deny_qos") != 0)\r
1091                                 {\r
1092                                         // 管理オプションで禁止されている\r
1093                                         qos = false;\r
1094                                         policy->NoQoS = true;\r
1095                                 }\r
1096                         }\r
1097 \r
1098                         if (GetHubAdminOption(hub, "max_bitrates_download") != 0)\r
1099                         {\r
1100                                 if (policy->MaxDownload == 0)\r
1101                                 {\r
1102                                         policy->MaxDownload = GetHubAdminOption(hub, "max_bitrates_download");\r
1103                                 }\r
1104                                 else\r
1105                                 {\r
1106                                         policy->MaxDownload = MIN(policy->MaxDownload, GetHubAdminOption(hub, "max_bitrates_download"));\r
1107                                 }\r
1108                         }\r
1109 \r
1110                         if (GetHubAdminOption(hub, "max_bitrates_upload") != 0)\r
1111                         {\r
1112                                 if (policy->MaxUpload == 0)\r
1113                                 {\r
1114                                         policy->MaxUpload = GetHubAdminOption(hub, "max_bitrates_upload");\r
1115                                 }\r
1116                                 else\r
1117                                 {\r
1118                                         policy->MaxUpload = MIN(policy->MaxUpload, GetHubAdminOption(hub, "max_bitrates_upload"));\r
1119                                 }\r
1120                         }\r
1121 \r
1122                         if (GetHubAdminOption(hub, "deny_bridge") != 0)\r
1123                         {\r
1124                                 policy->NoBridge = true;\r
1125                         }\r
1126 \r
1127                         if (GetHubAdminOption(hub, "deny_routing") != 0)\r
1128                         {\r
1129                                 policy->NoRouting = true;\r
1130                         }\r
1131 \r
1132                         if (hub->Option->ClientMinimumRequiredBuild > c->ClientBuild &&\r
1133                                  InStrEx(c->ClientStr, "client", false))\r
1134                         {\r
1135                                 // クライアントのビルド番号が小さすぎる\r
1136                                 HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, hub->Option->ClientMinimumRequiredBuild);\r
1137 \r
1138                                 Unlock(hub->lock);\r
1139                                 ReleaseHub(hub);\r
1140                                 c->Err = ERR_VERSION_INVALID;\r
1141                                 Free(policy);\r
1142                                 goto CLEANUP;\r
1143                         }\r
1144 \r
1145                         if (hub->Option->RequiredClientId != 0 &&\r
1146                                 hub->Option->RequiredClientId != client_id && \r
1147                                 InStrEx(c->ClientStr, "client", false))\r
1148                         {\r
1149                                 // クライアントのビルド番号が小さすぎる\r
1150                                 HLog(hub, "LH_CLIENT_ID_REQUIRED", c->Name, client_id, hub->Option->RequiredClientId);\r
1151 \r
1152                                 Unlock(hub->lock);\r
1153                                 ReleaseHub(hub);\r
1154                                 c->Err = ERR_CLIENT_ID_REQUIRED;\r
1155                                 Free(policy);\r
1156                                 goto CLEANUP;\r
1157                         }\r
1158 \r
1159                         if ((policy->NoSavePassword) || (policy->AutoDisconnect != 0))\r
1160                         {\r
1161                                 if (c->ClientBuild < 6560 && InStrEx(c->ClientStr, "client", false))\r
1162                                 {\r
1163                                         // NoSavePassword ポリシーが指定されている場合は対応クライアント\r
1164                                         // でなければ接続できない\r
1165                                         HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, 6560);\r
1166 \r
1167                                         Unlock(hub->lock);\r
1168                                         ReleaseHub(hub);\r
1169                                         c->Err = ERR_VERSION_INVALID;\r
1170                                         Free(policy);\r
1171                                         goto CLEANUP;\r
1172                                 }\r
1173                         }\r
1174 \r
1175                         if (user_expires != 0 && user_expires <= SystemTime64())\r
1176                         {\r
1177                                 // 有効期限が切れている\r
1178                                 // アクセスが拒否されている\r
1179                                 HLog(hub, "LH_USER_EXPIRES", c->Name, username);\r
1180 \r
1181                                 Unlock(hub->lock);\r
1182                                 ReleaseHub(hub);\r
1183                                 c->Err = ERR_ACCESS_DENIED;\r
1184                                 Free(policy);\r
1185                                 goto CLEANUP;\r
1186                         }\r
1187 \r
1188                         if (policy->Access == false)\r
1189                         {\r
1190                                 // アクセスが拒否されている\r
1191                                 HLog(hub, "LH_POLICY_ACCESS_NG", c->Name, username);\r
1192 \r
1193                                 Unlock(hub->lock);\r
1194                                 ReleaseHub(hub);\r
1195                                 c->Err = ERR_ACCESS_DENIED;\r
1196                                 Free(policy);\r
1197                                 goto CLEANUP;\r
1198                         }\r
1199 \r
1200                         // ポリシーの内容をクライアントが要求したオプションと比較して\r
1201                         // 決定するか接続を拒否する\r
1202                         // 最初にモニタポートモードで接続できるかどうか確認する\r
1203                         if (require_monitor_mode && policy->MonitorPort == false)\r
1204                         {\r
1205                                 // モニタポートモードで接続できない\r
1206                                 HLog(hub, "LH_POLICY_MONITOR_MODE", c->Name);\r
1207 \r
1208                                 Unlock(hub->lock);\r
1209                                 ReleaseHub(hub);\r
1210                                 c->Err = ERR_MONITOR_MODE_DENIED;\r
1211                                 Free(policy);\r
1212                                 goto CLEANUP;\r
1213                         }\r
1214 \r
1215                         if (policy->MonitorPort)\r
1216                         {\r
1217                                 if (require_monitor_mode == false)\r
1218                                 {\r
1219                                         policy->MonitorPort = false;\r
1220                                 }\r
1221                         }\r
1222 \r
1223                         if (policy->MonitorPort)\r
1224                         {\r
1225                                 qos = false;\r
1226                         }\r
1227 \r
1228                         // 次にブリッジ / ルーティングモードで接続できるか確認する\r
1229                         if (require_bridge_routing_mode &&\r
1230                                 (policy->NoBridge && policy->NoRouting))\r
1231                         {\r
1232                                 // ブリッジ / ルーティングモードで接続できない\r
1233                                 HLog(hub, "LH_POLICY_BRIDGE_MODE", c->Name);\r
1234 \r
1235                                 Unlock(hub->lock);\r
1236                                 ReleaseHub(hub);\r
1237                                 c->Err = ERR_BRIDGE_MODE_DENIED;\r
1238                                 Free(policy);\r
1239                                 goto CLEANUP;\r
1240                         }\r
1241 \r
1242                         if (require_bridge_routing_mode == false)\r
1243                         {\r
1244                                 policy->NoBridge = true;\r
1245                                 policy->NoRouting = true;\r
1246                         }\r
1247 \r
1248                         // ライセンスが必要かどうかチェック\r
1249                         GenerateMachineUniqueHash(unique2);\r
1250 \r
1251                         if (Cmp(unique, unique2, SHA1_SIZE) == 0)\r
1252                         {\r
1253                                 // ローカルホストセッションである\r
1254                                 local_host_session = true;\r
1255                         }\r
1256                         else\r
1257                         {\r
1258                                 if (license.NumUserLicense != INFINITE)\r
1259                                 {\r
1260                                         // ユーザー作成数が制限されているエディションでは多重ログイン禁止\r
1261                                         policy->MultiLogins = 1;\r
1262                                 }\r
1263 \r
1264                                 if (policy->NoBridge == false || policy->NoRouting == false)\r
1265                                 {\r
1266                                         // ブリッジライセンスを消費\r
1267                                         use_bridge_license = true;\r
1268                                 }\r
1269                                 else\r
1270                                 {\r
1271                                         // クライアントライセンスを消費\r
1272                                         use_client_license = true;\r
1273                                 }\r
1274                         }\r
1275 \r
1276                         if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&\r
1277                                 (use_bridge_license || use_client_license))\r
1278                         {\r
1279                                 // クラスタコントローラまたはスタンドアロンサーバーの場合で\r
1280                                 // クライアントにライセンスが必要になった場合、ここでライセンス数が\r
1281                                 // 足りているかどうかを計算する\r
1282 \r
1283                                 if (use_client_license)\r
1284                                 {\r
1285                                         if (server->CurrentAssignedClientLicense >= license.NumClientLicense)\r
1286                                         {\r
1287                                                 // クライアント接続ライセンスが足りない\r
1288                                                 Unlock(hub->lock);\r
1289 \r
1290                                                 // 詳細エラーログを吐く\r
1291                                                 HLog(hub, "LH_NOT_ENOUGH_CLIENT_LICENSE", c->Name,\r
1292                                                         license.NumClientLicense,\r
1293                                                         server->CurrentAssignedClientLicense + 1);\r
1294 \r
1295                                                 ReleaseHub(hub);\r
1296                                                 c->Err = ERR_CLIENT_LICENSE_NOT_ENOUGH;\r
1297                                                 Free(policy);\r
1298                                                 goto CLEANUP;\r
1299                                         }\r
1300                                 }\r
1301                                 if (use_bridge_license)\r
1302                                 {\r
1303                                         if (server->CurrentAssignedBridgeLicense >= license.NumBridgeLicense)\r
1304                                         {\r
1305                                                 // ブリッジ接続ライセンス数が足りない\r
1306                                                 Unlock(hub->lock);\r
1307 \r
1308                                                 // 詳細エラーログを吐く\r
1309                                                 HLog(hub, "LH_NOT_ENOUGH_BRIDGE_LICENSE", c->Name,\r
1310                                                         license.NumBridgeLicense,\r
1311                                                         server->CurrentAssignedBridgeLicense + 1);\r
1312 \r
1313                                                 ReleaseHub(hub);\r
1314                                                 c->Err = ERR_BRIDGE_LICENSE_NOT_ENOUGH;\r
1315                                                 Free(policy);\r
1316                                                 goto CLEANUP;\r
1317                                         }\r
1318                                 }\r
1319                         }\r
1320 \r
1321                         if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&\r
1322                                 policy != NULL)\r
1323                         {\r
1324                                 if (GetServerCapsBool(hub->Cedar->Server, "b_support_limit_multilogin"))\r
1325                                 {\r
1326                                         // ポリシーで多重ログイン制限数が指定されている場合は確認する\r
1327                                         RPC_ENUM_SESSION t;\r
1328                                         UINT i, num;\r
1329                                         UINT max_logins = policy->MultiLogins;\r
1330                                         UINT ao = GetHubAdminOption(hub, "max_multilogins_per_user");\r
1331 \r
1332                                         if (ao != 0)\r
1333                                         {\r
1334                                                 if (max_logins != 0)\r
1335                                                 {\r
1336                                                         max_logins = MIN(max_logins, ao);\r
1337                                                 }\r
1338                                                 else\r
1339                                                 {\r
1340                                                         max_logins = ao;\r
1341                                                 }\r
1342                                         }\r
1343 \r
1344                                         if (max_logins != 0)\r
1345                                         {\r
1346                                                 Zero(&t, sizeof(t));\r
1347                                                 StrCpy(t.HubName, sizeof(t.HubName), hub->Name);\r
1348 \r
1349                                                 Unlock(hub->lock);\r
1350 \r
1351                                                 SiEnumSessionMain(server, &t);\r
1352 \r
1353                                                 Lock(hub->lock);\r
1354 \r
1355                                                 num = 0;\r
1356 \r
1357                                                 for (i = 0;i < t.NumSession;i++)\r
1358                                                 {\r
1359                                                         RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];\r
1360 \r
1361                                                         if (e->BridgeMode == false && e->Layer3Mode == false && e->LinkMode == false && e->CurrentNumTcp != 0)\r
1362                                                         {\r
1363                                                                 if (StrCmpi(e->Username, username) == 0 &&\r
1364                                                                         (IsZero(e->UniqueId, 16) || Cmp(e->UniqueId, node.UniqueId, 16) != 0))\r
1365                                                                 {\r
1366                                                                         num++;\r
1367                                                                 }\r
1368                                                         }\r
1369                                                 }\r
1370 \r
1371                                                 FreeRpcEnumSession(&t);\r
1372 \r
1373                                                 if (num >= max_logins)\r
1374                                                 {\r
1375                                                         // これ以上接続できない\r
1376                                                         Unlock(hub->lock);\r
1377 \r
1378                                                         // 詳細エラーログを吐く\r
1379                                                         HLog(hub, license.NumUserLicense == INFINITE ? "LH_TOO_MANY_MULTILOGINS" : "LH_TOO_MANY_MULTILOGINS2",\r
1380                                                                 c->Name,\r
1381                                                                 username, max_logins, num);\r
1382 \r
1383                                                         ReleaseHub(hub);\r
1384                                                         c->Err = ERR_TOO_MANY_USER_SESSION;\r
1385                                                         Free(policy);\r
1386                                                         goto CLEANUP;\r
1387                                                 }\r
1388                                         }\r
1389                                 }\r
1390                         }\r
1391 \r
1392                         if (loggedin_user_object != NULL)\r
1393                         {\r
1394                                 // ユーザー情報の更新\r
1395                                 Lock(loggedin_user_object->lock);\r
1396                                 {\r
1397                                         loggedin_user_object->NumLogin++;\r
1398                                         loggedin_user_object->LastLoginTime = SystemTime64();\r
1399                                 }\r
1400                                 Unlock(loggedin_user_object->lock);\r
1401                         }\r
1402 \r
1403                         // ログイン回数を更新する\r
1404                         hub->NumLogin++;\r
1405                         hub->LastCommTime = hub->LastLoginTime = SystemTime64();\r
1406 \r
1407                         if (farm_controller)\r
1408                         {\r
1409                                 wchar_t *msg = GetHubMsg(hub);\r
1410 \r
1411                                 Unlock(hub->lock);\r
1412 \r
1413                                 Lock(cedar->CedarSuperLock);\r
1414 \r
1415                                 // ファームコントローラの場合、この HUB をホスティングする\r
1416                                 // ファームメンバを選定する\r
1417                                 LockList(server->FarmMemberList);\r
1418                                 {\r
1419                                         HLog(hub, "LH_FARM_SELECT_1", c->Name);\r
1420                                         f = SiGetHubHostingMember(server, hub, admin_mode);\r
1421 \r
1422                                         if (f == NULL)\r
1423                                         {\r
1424                                                 // 選定に失敗した\r
1425                                                 HLog(hub, "LH_FARM_SELECT_2", c->Name);\r
1426                                                 UnlockList(server->FarmMemberList);\r
1427                                                 Unlock(cedar->CedarSuperLock);\r
1428                                                 ReleaseHub(hub);\r
1429                                                 c->Err = ERR_COULD_NOT_HOST_HUB_ON_FARM;\r
1430                                                 Free(policy);\r
1431                                                 Free(msg);\r
1432                                                 goto CLEANUP;\r
1433                                         }\r
1434                                         else\r
1435                                         {\r
1436                                                 if (f->Me == false)\r
1437                                                 {\r
1438                                                         UCHAR ticket[SHA1_SIZE];\r
1439                                                         PACK *p;\r
1440                                                         BUF *b;\r
1441                                                         UINT i;\r
1442 \r
1443                                                         SLog(c->Cedar, "LH_FARM_SELECT_4", c->Name, f->hostname);\r
1444 \r
1445                                                         // 選定したサーバーファームメンバにセッションを作成する\r
1446                                                         Rand(ticket, sizeof(ticket));\r
1447                                                         SiCallCreateTicket(server, f, hub->Name,\r
1448                                                                 username, username_real, policy, ticket, Inc(hub->SessionCounter), groupname);\r
1449 \r
1450                                                         p = NewPack();\r
1451                                                         PackAddInt(p, "Redirect", 1);\r
1452                                                         PackAddIp32(p, "Ip", f->Ip);\r
1453                                                         for (i = 0;i < f->NumPort;i++)\r
1454                                                         {\r
1455                                                                 PackAddIntEx(p, "Port", f->Ports[i], i, f->NumPort);\r
1456                                                         }\r
1457                                                         PackAddData(p, "Ticket", ticket, sizeof(ticket));\r
1458 \r
1459                                                         if (true)\r
1460                                                         {\r
1461                                                                 char *utf = CopyUniToUtf(msg);\r
1462 \r
1463                                                                 PackAddData(p, "Msg", utf, StrLen(utf));\r
1464 \r
1465                                                                 Free(utf);\r
1466                                                         }\r
1467 \r
1468                                                         b = XToBuf(f->ServerCert, false);\r
1469                                                         PackAddBuf(p, "Cert", b);\r
1470                                                         FreeBuf(b);\r
1471 \r
1472                                                         UnlockList(server->FarmMemberList);\r
1473                                                         Unlock(cedar->CedarSuperLock);\r
1474                                                         ReleaseHub(hub);\r
1475 \r
1476                                                         HttpServerSend(c->FirstSock, p);\r
1477                                                         FreePack(p);\r
1478 \r
1479                                                         c->Err = 0;\r
1480                                                         Free(policy);\r
1481 \r
1482                                                         FreePack(HttpServerRecv(c->FirstSock));\r
1483                                                         Free(msg);\r
1484                                                         goto CLEANUP;\r
1485                                                 }\r
1486                                                 else\r
1487                                                 {\r
1488                                                         HLog(hub, "LH_FARM_SELECT_3", c->Name);\r
1489                                                         // 自分自身が選定されたのでこのまま続ける\r
1490                                                         UnlockList(server->FarmMemberList);\r
1491                                                         Unlock(cedar->CedarSuperLock);\r
1492                                                         f->Point = SiGetPoint(server);\r
1493                                                         Lock(hub->lock);\r
1494                                                         Free(msg);\r
1495                                                 }\r
1496                                         }\r
1497                                 }\r
1498                         }\r
1499 \r
1500                         if (admin_mode == false)\r
1501                         {\r
1502                                 // HUB の最大接続数をチェック\r
1503                                 if (hub->Option->MaxSession != 0 &&\r
1504                                         hub->Option->MaxSession <= Count(hub->NumSessions))\r
1505                                 {\r
1506                                         // これ以上接続できない\r
1507                                         Unlock(hub->lock);\r
1508 \r
1509                                         HLog(hub, "LH_MAX_SESSION", c->Name, hub->Option->MaxSession);\r
1510 \r
1511                                         ReleaseHub(hub);\r
1512                                         c->Err = ERR_HUB_IS_BUSY;\r
1513                                         Free(policy);\r
1514                                         goto CLEANUP;\r
1515                                 }\r
1516                         }\r
1517 \r
1518                         if (use_client_license || use_bridge_license)\r
1519                         {\r
1520                                 // 仮想 HUB 管理オプションで規定された同時接続セッション数\r
1521                                 // の制限に抵触しないかどうか調べる\r
1522                                 if (\r
1523                                         (GetHubAdminOption(hub, "max_sessions") != 0 &&\r
1524                                         (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= GetHubAdminOption(hub, "max_sessions"))\r
1525                                         ||\r
1526                                         (hub->Option->MaxSession != 0 &&\r
1527                                         (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= hub->Option->MaxSession))\r
1528                                 {\r
1529                                         // これ以上接続できない\r
1530                                         Unlock(hub->lock);\r
1531 \r
1532                                         HLog(hub, "LH_MAX_SESSION", c->Name, GetHubAdminOption(hub, "max_sessions"));\r
1533 \r
1534                                         ReleaseHub(hub);\r
1535                                         c->Err = ERR_HUB_IS_BUSY;\r
1536                                         Free(policy);\r
1537                                         goto CLEANUP;\r
1538                                 }\r
1539                         }\r
1540 \r
1541                         if (use_client_license)\r
1542                         {\r
1543                                 // 仮想 HUB 管理オプションで規定された同時接続セッション数 (クライアント)\r
1544                                 // の制限に抵触しないかどうか調べる\r
1545                                 if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition) &&\r
1546                                         Count(hub->NumSessionsClient) >= GetHubAdminOption(hub, "max_sessions_client") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)\r
1547                                         ||\r
1548                                         (hub->FarmMember_MaxSessionClientBridgeApply &&\r
1549                                         Count(hub->NumSessionsClient) >= hub->FarmMember_MaxSessionClient))\r
1550                                 {\r
1551                                         // これ以上接続できない\r
1552                                         Unlock(hub->lock);\r
1553 \r
1554                                         HLog(hub, "LH_MAX_SESSION_CLIENT", c->Name, GetHubAdminOption(hub, "max_sessions_client"));\r
1555 \r
1556                                         ReleaseHub(hub);\r
1557                                         c->Err = ERR_HUB_IS_BUSY;\r
1558                                         Free(policy);\r
1559                                         goto CLEANUP;\r
1560                                 }\r
1561                         }\r
1562 \r
1563                         if (use_bridge_license)\r
1564                         {\r
1565                                 // 仮想 HUB 管理オプションで規定された同時接続セッション数 (ブリッジ)\r
1566                                 // の制限に抵触しないかどうか調べる\r
1567                                 if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition) &&\r
1568                                         Count(hub->NumSessionsBridge) >= GetHubAdminOption(hub, "max_sessions_bridge") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)\r
1569                                         ||\r
1570                                         (hub->FarmMember_MaxSessionClientBridgeApply &&\r
1571                                         Count(hub->NumSessionsBridge) >= hub->FarmMember_MaxSessionBridge))\r
1572                                 {\r
1573                                         // これ以上接続できない\r
1574                                         Unlock(hub->lock);\r
1575 \r
1576                                         HLog(hub, "LH_MAX_SESSION_BRIDGE", c->Name, GetHubAdminOption(hub, "max_sessions_bridge"));\r
1577 \r
1578                                         ReleaseHub(hub);\r
1579                                         c->Err = ERR_HUB_IS_BUSY;\r
1580                                         Free(policy);\r
1581                                         goto CLEANUP;\r
1582                                 }\r
1583                         }\r
1584 \r
1585                         if (Count(hub->Cedar->CurrentSessions) >= GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"))\r
1586                         {\r
1587                                 // これ以上接続できない\r
1588                                 Unlock(hub->lock);\r
1589 \r
1590                                 HLog(hub, "LH_MAX_SESSION_2", c->Name, GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"));\r
1591 \r
1592                                 ReleaseHub(hub);\r
1593                                 c->Err = ERR_HUB_IS_BUSY;\r
1594                                 Free(policy);\r
1595                                 goto CLEANUP;\r
1596                         }\r
1597 \r
1598                         // 現在の接続数をインクリメント\r
1599                         Inc(hub->NumSessions);\r
1600                         if (use_bridge_license)\r
1601                         {\r
1602                                 Inc(hub->NumSessionsBridge);\r
1603                         }\r
1604 \r
1605                         if (use_client_license)\r
1606                         {\r
1607                                 Inc(hub->NumSessionsClient);\r
1608                         }\r
1609                         Inc(hub->Cedar->CurrentSessions);\r
1610 \r
1611                         // タイムアウト時間を計算\r
1612                         timeout = policy->TimeOut * 1000;       // ミリ秒 → 秒 に変換\r
1613                         if (timeout == 0)\r
1614                         {\r
1615                                 timeout = TIMEOUT_DEFAULT;\r
1616                         }\r
1617                         timeout = MIN(timeout, TIMEOUT_MAX);\r
1618                         timeout = MAX(timeout, TIMEOUT_MIN);\r
1619 \r
1620                         // ポリシーに応じて max_connection を更新\r
1621                         max_connection = MIN(max_connection, policy->MaxConnection);\r
1622                         max_connection = MIN(max_connection, MAX_TCP_CONNECTION);\r
1623                         max_connection = MAX(max_connection, 1);\r
1624                         if (half_connection)\r
1625                         {\r
1626                                 // Half Connection 時にはコネクション数は 2 以上とする\r
1627                                 max_connection = MAX(max_connection, 2);\r
1628                         }\r
1629 \r
1630                         if (qos)\r
1631                         {\r
1632                                 // VoIP / QoS 使用時にはコネクション数は 2 以上とする\r
1633                                 max_connection = MAX(max_connection, 2);\r
1634                                 if (half_connection)\r
1635                                 {\r
1636                                         max_connection = MAX(max_connection, 4);\r
1637                                 }\r
1638                         }\r
1639 \r
1640                         c->Status = CONNECTION_STATUS_ESTABLISHED;\r
1641 \r
1642                         // コネクションを Cedar から削除\r
1643                         DelConnection(c->Cedar, c);\r
1644 \r
1645                         // セッションの作成\r
1646                         StrLower(username);\r
1647                         s = NewServerSession(c->Cedar, c, hub, username, policy);\r
1648 \r
1649                         if (server != NULL)\r
1650                         {\r
1651                                 s->NoSendSignature = server->NoSendSignature;\r
1652                         }\r
1653 \r
1654                         s->UseClientLicense = use_client_license;\r
1655                         s->UseBridgeLicense = use_bridge_license;\r
1656 \r
1657                         s->IsBridgeMode = (policy->NoBridge == false) || (policy->NoRouting == false);\r
1658                         s->IsMonitorMode = policy->MonitorPort;\r
1659 \r
1660                         // IPv6 セッションかどうかの判定\r
1661                         s->IPv6Session = false;\r
1662 \r
1663                         if (node.ClientIpAddress == 0)\r
1664                         {\r
1665                                 s->IPv6Session = true;\r
1666                         }\r
1667 \r
1668                         if (use_bridge_license)\r
1669                         {\r
1670                                 Inc(s->Cedar->AssignedBridgeLicense);\r
1671                         }\r
1672 \r
1673                         if (use_client_license)\r
1674                         {\r
1675                                 Inc(s->Cedar->AssignedClientLicense);\r
1676                         }\r
1677 \r
1678                         if (server != NULL)\r
1679                         {\r
1680                                 // Server 構造体の合計割り当て済みライセンス数の更新\r
1681                                 if (server->ServerType == SERVER_TYPE_STANDALONE)\r
1682                                 {\r
1683                                         // スタンドアロンモードのみ更新\r
1684                                         // (クラスタコントローラモードでは定期的にポーリングしている)\r
1685                                         server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);\r
1686                                         server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);\r
1687                                 }\r
1688                         }\r
1689 \r
1690                         if (StrLen(sessionname) != 0)\r
1691                         {\r
1692                                 // セッション名の指定\r
1693                                 Free(s->Name);\r
1694                                 s->Name = CopyStr(sessionname);\r
1695                         }\r
1696 \r
1697                         {\r
1698                                 char ip[128];\r
1699                                 IPToStr(ip, sizeof(ip), &c->FirstSock->RemoteIP);\r
1700                                 HLog(hub, "LH_NEW_SESSION", c->Name, s->Name, ip, c->FirstSock->RemotePort);\r
1701                         }\r
1702 \r
1703                         c->Session = s;\r
1704                         s->AdministratorMode = admin_mode;\r
1705                         StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username_real);\r
1706                         StrCpy(s->GroupName, sizeof(s->GroupName), groupname);\r
1707 \r
1708                         // セッションキーの取得\r
1709                         Copy(session_key, s->SessionKey, SHA1_SIZE);\r
1710 \r
1711                         // パラメータをセット\r
1712                         s->MaxConnection = max_connection;\r
1713                         s->UseEncrypt = use_encrypt;\r
1714                         if (s->UseEncrypt && use_fast_rc4)\r
1715                         {\r
1716                                 s->UseFastRC4 = use_fast_rc4;\r
1717                         }\r
1718                         s->UseCompress = use_compress;\r
1719                         s->HalfConnection = half_connection;\r
1720                         s->Timeout = timeout;\r
1721                         s->QoS = qos;\r
1722 \r
1723                         if (policy != NULL)\r
1724                         {\r
1725                                 s->VLanId = policy->VLanId;\r
1726                         }\r
1727 \r
1728                         // ユーザー名\r
1729                         s->Username = CopyStr(username);\r
1730 \r
1731                         HLog(hub, "LH_SET_SESSION", s->Name, s->MaxConnection,\r
1732                                 s->UseEncrypt ? _UU("L_YES") : _UU("L_NO"),\r
1733                                 s->UseCompress ? _UU("L_YES") : _UU("L_NO"),\r
1734                                 s->HalfConnection ? _UU("L_YES") : _UU("L_NO"),\r
1735                                 s->Timeout / 1000);\r
1736 \r
1737                         msg = GetHubMsg(hub);\r
1738                 }\r
1739                 Unlock(hub->lock);\r
1740 \r
1741                 // クライアントに Welcome パケットを送信\r
1742                 p = PackWelcome(s);\r
1743 \r
1744                 if (true)\r
1745                 {\r
1746                         // VPN Client に表示するメッセージ\r
1747                         char *utf;\r
1748                         wchar_t winver_msg_client[3800];\r
1749                         wchar_t winver_msg_server[3800];\r
1750                         wchar_t *utvpn_msg;\r
1751                         UINT tmpsize;\r
1752                         wchar_t *tmp;\r
1753                         RPC_WINVER server_winver;\r
1754 \r
1755                         GetWinVer(&server_winver);\r
1756 \r
1757                         Zero(winver_msg_client, sizeof(winver_msg_client));\r
1758                         Zero(winver_msg_server, sizeof(winver_msg_server));\r
1759 \r
1760                         utvpn_msg = _UU("UTVPN_MSG");\r
1761 \r
1762                         if (IsSupportedWinVer(&winver) == false)\r
1763                         {\r
1764                                 SYSTEMTIME st;\r
1765 \r
1766                                 LocalTime(&st);\r
1767 \r
1768                                 UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),\r
1769                                         _UU("WINVER_ERROR_PC_LOCAL"),\r
1770                                         winver.Title,\r
1771                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1772                                         SUPPORTED_WINDOWS_LIST,\r
1773                                         _UU("WINVER_ERROR_PC_LOCAL"),\r
1774                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1775                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1776                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1777                                         st.wYear, st.wMonth);\r
1778                         }\r
1779 \r
1780                         if (IsSupportedWinVer(&server_winver) == false)\r
1781                         {\r
1782                                 SYSTEMTIME st;\r
1783 \r
1784                                 LocalTime(&st);\r
1785 \r
1786                                 UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),\r
1787                                         _UU("WINVER_ERROR_PC_REMOTE"),\r
1788                                         server_winver.Title,\r
1789                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1790                                         SUPPORTED_WINDOWS_LIST,\r
1791                                         _UU("WINVER_ERROR_PC_REMOTE"),\r
1792                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1793                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1794                                         _UU("WINVER_ERROR_VPNSERVER"),\r
1795                                         st.wYear, st.wMonth);\r
1796                         }\r
1797 \r
1798                         tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + UniStrSize(utvpn_msg) + UniStrSize(msg) * 100;\r
1799 \r
1800                         tmp = ZeroMalloc(tmpsize);\r
1801 \r
1802                         if (IsURLMsg(msg, NULL, 0) == false)\r
1803                         {\r
1804                                 UniStrCat(tmp, tmpsize, utvpn_msg);\r
1805                                 UniStrCat(tmp, tmpsize, winver_msg_client);\r
1806                                 UniStrCat(tmp, tmpsize, winver_msg_server);\r
1807                         }\r
1808                         UniStrCat(tmp, tmpsize, msg);\r
1809                         \r
1810                         utf = CopyUniToUtf(tmp);\r
1811 \r
1812                         PackAddData(p, "Msg", utf, StrLen(utf));\r
1813 \r
1814                         Free(tmp);\r
1815                         Free(utf);\r
1816                 }\r
1817 \r
1818                 Free(msg);\r
1819 \r
1820                 if (s->UseFastRC4)\r
1821                 {\r
1822                         // RC4 キーペアを生成\r
1823                         GenerateRC4KeyPair(&key_pair);\r
1824 \r
1825                         // Welcome パケットに追加\r
1826                         PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));\r
1827                         PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));\r
1828                         {\r
1829                                 char key1[64], key2[64];\r
1830                                 BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);\r
1831                                 BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);\r
1832                                 Debug(\r
1833                                         "Client to Server Key: %s\n"\r
1834                                         "Server to Client Key: %s\n",\r
1835                                         key1, key2);\r
1836                         }\r
1837                 }\r
1838                 HttpServerSend(c->FirstSock, p);\r
1839                 FreePack(p);\r
1840 \r
1841                 Copy(&c->Session->NodeInfo, &node, sizeof(NODE_INFO));\r
1842                 {\r
1843                         wchar_t tmp[MAX_SIZE * 2];\r
1844                         NodeInfoToStr(tmp, sizeof(tmp), &s->NodeInfo);\r
1845 \r
1846                         HLog(hub, "LH_NODE_INFO", s->Name, tmp);\r
1847                 }\r
1848 \r
1849                 // コネクションをトンネリングモードに移行\r
1850                 StartTunnelingMode(c);\r
1851 \r
1852                 // ハーフコネクションモード時の処理\r
1853                 if (s->HalfConnection)\r
1854                 {\r
1855                         // 1 つ目のソケットはクライアント→サーバー 方向 とする\r
1856                         TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);\r
1857                         ts->Direction = TCP_CLIENT_TO_SERVER;\r
1858                 }\r
1859 \r
1860                 if (s->UseFastRC4)\r
1861                 {\r
1862                         // 1 つ目の TCP コネクションに RC4 キー情報をセットする\r
1863                         TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);\r
1864                         Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));\r
1865 \r
1866                         InitTcpSockRc4Key(ts, true);\r
1867                 }\r
1868 \r
1869                 if (s->UseEncrypt && s->UseFastRC4 == false)\r
1870                 {\r
1871                         s->UseSSLDataEncryption = true;\r
1872                 }\r
1873                 else\r
1874                 {\r
1875                         s->UseSSLDataEncryption = false;\r
1876                 }\r
1877 \r
1878                 if (s->Hub->Type == HUB_TYPE_FARM_DYNAMIC && s->Cedar->Server != NULL && s->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)\r
1879                 {\r
1880                         if (s->Hub->BeingOffline == false)\r
1881                         {\r
1882                                 // ダイナミック仮想 HUB で SecureNAT を開始\r
1883                                 EnableSecureNATEx(s->Hub, false, true);\r
1884 \r
1885                                 cluster_dynamic_secure_nat = true;\r
1886                         }\r
1887                 }\r
1888 \r
1889                 // セッションのメインルーチン\r
1890                 SessionMain(s);\r
1891 \r
1892                 // 現在の接続数をデクリメント\r
1893                 Lock(s->Hub->lock);\r
1894                 {\r
1895                         if (use_bridge_license)\r
1896                         {\r
1897                                 Dec(hub->NumSessionsBridge);\r
1898                         }\r
1899 \r
1900                         if (use_client_license)\r
1901                         {\r
1902                                 Dec(hub->NumSessionsClient);\r
1903                         }\r
1904 \r
1905                         Dec(s->Hub->NumSessions);\r
1906                         Dec(s->Hub->Cedar->CurrentSessions);\r
1907 \r
1908                         // ライセンス数のデクリメント\r
1909                         if (use_bridge_license)\r
1910                         {\r
1911                                 Dec(s->Cedar->AssignedBridgeLicense);\r
1912                         }\r
1913 \r
1914                         if (use_client_license)\r
1915                         {\r
1916                                 Dec(s->Cedar->AssignedClientLicense);\r
1917                         }\r
1918 \r
1919                         if (server != NULL)\r
1920                         {\r
1921                                 // Server 構造体の合計割り当て済みライセンス数の更新\r
1922                                 if (server->ServerType == SERVER_TYPE_STANDALONE)\r
1923                                 {\r
1924                                         // スタンドアロンモードのみ更新\r
1925                                         // (クラスタコントローラモードでは定期的にポーリングしている)\r
1926                                         server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);\r
1927                                         server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);\r
1928                                 }\r
1929                         }\r
1930                 }\r
1931                 Unlock(s->Hub->lock);\r
1932 \r
1933                 PrintSessionTotalDataSize(s);\r
1934 \r
1935                 HLog(s->Hub, "LH_END_SESSION", s->Name, s->TotalSendSizeReal, s->TotalRecvSizeReal);\r
1936 \r
1937                 if (cluster_dynamic_secure_nat && s->Hub->BeingOffline == false)\r
1938                 {\r
1939                         // ダイナミック仮想 HUB で SecureNAT を停止\r
1940                         EnableSecureNATEx(s->Hub, false, true);\r
1941                 }\r
1942 \r
1943                 ReleaseSession(s);\r
1944 \r
1945                 ret = true;\r
1946                 c->Err = ERR_SESSION_REMOVED;\r
1947 \r
1948                 ReleaseHub(hub);\r
1949 \r
1950                 goto CLEANUP;\r
1951         }\r
1952         else if (StrCmpi(method, "additional_connect") == 0)\r
1953         {\r
1954                 SOCK *sock;\r
1955                 TCPSOCK *ts;\r
1956                 UINT dummy;\r
1957 \r
1958                 c->Type = CONNECTION_TYPE_ADDITIONAL;\r
1959 \r
1960                 // 追加接続\r
1961                 // セッションキーを読み出し\r
1962                 if (GetSessionKeyFromPack(p, session_key, &dummy) == false)\r
1963                 {\r
1964                         FreePack(p);\r
1965                         c->Err = ERR_PROTOCOL_ERROR;\r
1966                         goto CLEANUP;\r
1967                 }\r
1968 \r
1969                 FreePack(p);\r
1970 \r
1971                 // セッションキーからセッションを取得\r
1972                 s = GetSessionFromKey(c->Cedar, session_key);\r
1973                 if (s == NULL || s->Halt)\r
1974                 {\r
1975                         // セッションが発見できない\r
1976                         Debug("Session Not Found.\n");\r
1977                         c->Err = ERR_SESSION_TIMEOUT;\r
1978                         goto CLEANUP;\r
1979                 }\r
1980 \r
1981                 // セッションが見つかった\r
1982                 Debug("Session Found: %s\n", s->Name);\r
1983                 // セッションのプロトコルを確認\r
1984                 c->Err = 0;\r
1985                 Lock(s->lock);\r
1986                 {\r
1987                         if (s->Connection->Protocol != CONNECTION_TCP)\r
1988                         {\r
1989                                 c->Err = ERR_INVALID_PROTOCOL;\r
1990                         }\r
1991                 }\r
1992                 Unlock(s->lock);\r
1993                 // セッションの現在のコネクション数を調べる\r
1994                 Lock(s->Connection->lock);\r
1995                 if (c->Err == 0)\r
1996                 {\r
1997                         if (Count(s->Connection->CurrentNumConnection) > s->MaxConnection)\r
1998                         {\r
1999                                 c->Err = ERR_TOO_MANY_CONNECTION;\r
2000                         }\r
2001                 }\r
2002                 if (c->Err != 0)\r
2003                 {\r
2004                         Unlock(s->Connection->lock);\r
2005                         if (c->Err == ERR_TOO_MANY_CONNECTION)\r
2006                         {\r
2007                                 Debug("Session TOO MANY CONNECTIONS !!: %u\n",\r
2008                                         Count(s->Connection->CurrentNumConnection));\r
2009                         }\r
2010                         else\r
2011                         {\r
2012                                 Debug("Session Invalid Protocol.\n");\r
2013                         }\r
2014                         ReleaseSession(s);\r
2015                         goto CLEANUP;\r
2016                 }\r
2017 \r
2018                 // RC4 高速暗号化鍵の生成\r
2019                 if (s->UseFastRC4)\r
2020                 {\r
2021                         GenerateRC4KeyPair(&key_pair);\r
2022                 }\r
2023 \r
2024                 // セッションのコネクションリスト (TCP) にこのコネクションのソケットを追加する\r
2025                 sock = c->FirstSock;\r
2026                 ts = NewTcpSock(sock);\r
2027                 SetTimeout(sock, CONNECTING_TIMEOUT);\r
2028                 direction = TCP_BOTH;\r
2029                 LockList(s->Connection->Tcp->TcpSockList);\r
2030                 {\r
2031                         if (s->HalfConnection)\r
2032                         {\r
2033                                 // ハーフコネクション時、現在のすべての TCP コネクションの方向を\r
2034                                 // 調べて自動的に調整する\r
2035                                 UINT i, c2s, s2c;\r
2036                                 c2s = s2c = 0;\r
2037                                 for (i = 0;i < LIST_NUM(s->Connection->Tcp->TcpSockList);i++)\r
2038                                 {\r
2039                                         TCPSOCK *ts = (TCPSOCK *)LIST_DATA(s->Connection->Tcp->TcpSockList, i);\r
2040                                         if (ts->Direction == TCP_SERVER_TO_CLIENT)\r
2041                                         {\r
2042                                                 s2c++;\r
2043                                         }\r
2044                                         else\r
2045                                         {\r
2046                                                 c2s++;\r
2047                                         }\r
2048                                 }\r
2049                                 if (s2c > c2s)\r
2050                                 {\r
2051                                         direction = TCP_CLIENT_TO_SERVER;\r
2052                                 }\r
2053                                 else\r
2054                                 {\r
2055                                         direction = TCP_SERVER_TO_CLIENT;\r
2056                                 }\r
2057                                 Debug("%u/%u\n", s2c, c2s);\r
2058                                 ts->Direction = direction;\r
2059                         }\r
2060                 }\r
2061                 UnlockList(s->Connection->Tcp->TcpSockList);\r
2062 \r
2063                 if (s->UseFastRC4)\r
2064                 {\r
2065                         // RC4 鍵情報の設定\r
2066                         Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));\r
2067 \r
2068                         InitTcpSockRc4Key(ts, true);\r
2069                 }\r
2070 \r
2071                 // 成功結果を返す\r
2072                 p = PackError(ERR_NO_ERROR);\r
2073                 PackAddInt(p, "direction", direction);\r
2074 \r
2075                 if (s->UseFastRC4)\r
2076                 {\r
2077                         // RC4 鍵情報の追加\r
2078                         PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));\r
2079                         PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));\r
2080                         {\r
2081                                 char key1[64], key2[64];\r
2082                                 BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);\r
2083                                 BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);\r
2084                                 Debug(\r
2085                                         "Client to Server Key: %s\n"\r
2086                                         "Server to Client Key: %s\n",\r
2087                                         key1, key2);\r
2088                         }\r
2089                 }\r
2090 \r
2091                 HttpServerSend(c->FirstSock, p);\r
2092                 FreePack(p);\r
2093 \r
2094                 SetTimeout(sock, INFINITE);\r
2095 \r
2096                 LockList(s->Connection->Tcp->TcpSockList);\r
2097                 {\r
2098                         Add(s->Connection->Tcp->TcpSockList, ts);\r
2099                 }\r
2100                 UnlockList(s->Connection->Tcp->TcpSockList);\r
2101 \r
2102                 // コネクション数をインクリメントする\r
2103                 Inc(s->Connection->CurrentNumConnection);\r
2104                 Debug("TCP Connection Incremented: %u\n", Count(s->Connection->CurrentNumConnection));\r
2105 \r
2106                 // セッションの Cancel を発行する\r
2107                 Cancel(s->Cancel1);\r
2108 \r
2109                 Unlock(s->Connection->lock);\r
2110 \r
2111                 c->flag1 = true;\r
2112 \r
2113                 ReleaseSession(s);\r
2114 \r
2115                 return true;\r
2116         }\r
2117         else if (StrCmpi(method, "enum_hub") == 0)\r
2118         {\r
2119                 // 仮想 HUB の列挙\r
2120                 UINT i, num;\r
2121                 LIST *o;\r
2122                 o = NewListFast(NULL);\r
2123 \r
2124                 c->Type = CONNECTION_TYPE_ENUM_HUB;\r
2125 \r
2126                 FreePack(p);\r
2127                 p = NewPack();\r
2128                 LockList(c->Cedar->HubList);\r
2129                 {\r
2130                         num = LIST_NUM(c->Cedar->HubList);\r
2131                         for (i = 0;i < num;i++)\r
2132                         {\r
2133                                 HUB *h = LIST_DATA(c->Cedar->HubList, i);\r
2134                                 if (h->Option != NULL && h->Option->NoEnum == false)\r
2135                                 {\r
2136                                         Insert(o, CopyStr(h->Name));\r
2137                                 }\r
2138                         }\r
2139                 }\r
2140                 UnlockList(c->Cedar->HubList);\r
2141 \r
2142                 num = LIST_NUM(o);\r
2143                 for (i = 0;i < num;i++)\r
2144                 {\r
2145                         char *name = LIST_DATA(o, i);\r
2146                         PackAddStrEx(p, "HubName", name, i, num);\r
2147                         Free(name);\r
2148                 }\r
2149                 ReleaseList(o);\r
2150                 PackAddInt(p, "NumHub", num);\r
2151 \r
2152                 HttpServerSend(c->FirstSock, p);\r
2153                 FreePack(p);\r
2154                 FreePack(HttpServerRecv(c->FirstSock));\r
2155                 c->Err = 0;\r
2156 \r
2157                 SLog(c->Cedar, "LS_ENUM_HUB", c->Name, num);\r
2158 \r
2159                 goto CLEANUP;\r
2160         }\r
2161         else if (StrCmpi(method, "farm_connect") == 0)\r
2162         {\r
2163                 // サーバーファーム接続要求\r
2164                 CEDAR *cedar = c->Cedar;\r
2165                 c->Type = CONNECTION_TYPE_FARM_RPC;\r
2166                 c->Err = 0;\r
2167                 if (c->Cedar->Server == NULL)\r
2168                 {\r
2169                         // サポートされていない\r
2170                         c->Err = ERR_NOT_FARM_CONTROLLER;\r
2171                 }\r
2172                 else\r
2173                 {\r
2174                         SERVER *s = c->Cedar->Server;\r
2175                         if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER || s->FarmControllerInited == false)\r
2176                         {\r
2177                                 // ファームコントローラではない\r
2178                                 SLog(c->Cedar, "LS_FARM_ACCEPT_1", c->Name);\r
2179                                 c->Err = ERR_NOT_FARM_CONTROLLER;\r
2180                         }\r
2181                         else\r
2182                         {\r
2183                                 UCHAR check_secure_password[SHA1_SIZE];\r
2184                                 UCHAR secure_password[SHA1_SIZE];\r
2185                                 // ユーザー認証\r
2186                                 SecurePassword(check_secure_password, s->HashedPassword, c->Random);\r
2187                                 if (PackGetDataSize(p, "SecurePassword") == sizeof(secure_password))\r
2188                                 {\r
2189                                         PackGetData(p, "SecurePassword", secure_password);\r
2190                                 }\r
2191                                 else\r
2192                                 {\r
2193                                         Zero(secure_password, sizeof(secure_password));\r
2194                                 }\r
2195 \r
2196                                 if (Cmp(secure_password, check_secure_password, SHA1_SIZE) != 0)\r
2197                                 {\r
2198                                         // パスワードが違う\r
2199                                         SLog(c->Cedar, "LS_FARM_ACCEPT_2", c->Name);\r
2200                                         c->Err = ERR_ACCESS_DENIED;\r
2201                                 }\r
2202                                 else\r
2203                                 {\r
2204                                         // 証明書を取得する\r
2205                                         BUF *b;\r
2206                                         X *server_x;\r
2207 \r
2208                                         SLog(c->Cedar, "LS_FARM_ACCEPT_3", c->Name);\r
2209                                         b = PackGetBuf(p, "ServerCert");\r
2210                                         if (b == NULL)\r
2211                                         {\r
2212                                                 c->Err = ERR_PROTOCOL_ERROR;\r
2213                                         }\r
2214                                         else\r
2215                                         {\r
2216                                                 server_x = BufToX(b, false);\r
2217                                                 FreeBuf(b);\r
2218                                                 if (server_x == NULL)\r
2219                                                 {\r
2220                                                         c->Err = ERR_PROTOCOL_ERROR;\r
2221                                                 }\r
2222                                                 else\r
2223                                                 {\r
2224                                                         UINT ip;\r
2225                                                         UINT point;\r
2226                                                         char hostname[MAX_SIZE];\r
2227 \r
2228 #ifdef  OS_WIN32\r
2229                                                         MsSetThreadPriorityRealtime();\r
2230 #endif  // OS_WIN32\r
2231 \r
2232                                                         SetTimeout(c->FirstSock, SERVER_CONTROL_TCP_TIMEOUT);\r
2233 \r
2234                                                         ip = PackGetIp32(p, "PublicIp");\r
2235                                                         point = PackGetInt(p, "Point");\r
2236                                                         if (PackGetStr(p, "HostName", hostname, sizeof(hostname)))\r
2237                                                         {\r
2238                                                                 UINT num_port = PackGetIndexCount(p, "PublicPort");\r
2239                                                                 if (num_port >= 1 && num_port <= MAX_PUBLIC_PORT_NUM)\r
2240                                                                 {\r
2241                                                                         UINT *ports = ZeroMalloc(sizeof(UINT) * num_port);\r
2242                                                                         UINT i;\r
2243 \r
2244                                                                         for (i = 0;i < num_port;i++)\r
2245                                                                         {\r
2246                                                                                 ports[i] = PackGetIntEx(p, "PublicPort", i);\r
2247                                                                         }\r
2248 \r
2249                                                                         SiFarmServ(s, c->FirstSock, server_x, ip, num_port, ports, hostname, point,\r
2250                                                                                 PackGetInt(p, "Weight"), PackGetInt(p, "MaxSessions"));\r
2251 \r
2252                                                                         Free(ports);\r
2253                                                                 }\r
2254                                                         }\r
2255 \r
2256                                                         FreeX(server_x);\r
2257                                                 }\r
2258                                         }\r
2259                                 }\r
2260                         }\r
2261                 }\r
2262                 FreePack(p);\r
2263                 goto CLEANUP;\r
2264         }\r
2265         else if (StrCmpi(method, "admin") == 0 && c->Cedar->Server != NULL)\r
2266         {\r
2267                 UINT err;\r
2268                 // 管理用 RPC 接続要求\r
2269                 c->Type = CONNECTION_TYPE_ADMIN_RPC;\r
2270                 err = AdminAccept(c, p);\r
2271                 FreePack(p);\r
2272                 if (err != ERR_NO_ERROR)\r
2273                 {\r
2274                         PACK *p = PackError(err);\r
2275                         HttpServerSend(c->FirstSock, p);\r
2276                         FreePack(p);\r
2277                 }\r
2278                 goto CLEANUP;\r
2279         }\r
2280         else if (StrCmpi(method, "password") == 0)\r
2281         {\r
2282                 UINT err;\r
2283                 // パスワード変更要求\r
2284                 c->Type = CONNECTION_TYPE_PASSWORD;\r
2285                 err = ChangePasswordAccept(c, p);\r
2286                 FreePack(p);\r
2287 \r
2288                 p = PackError(err);\r
2289                 HttpServerSend(c->FirstSock, p);\r
2290                 FreePack(p);\r
2291                 goto CLEANUP;\r
2292         }\r
2293         else\r
2294         {\r
2295                 // 不明なメソッド\r
2296                 FreePack(p);\r
2297                 c->Err = ERR_PROTOCOL_ERROR;\r
2298                 goto CLEANUP;\r
2299         }\r
2300 \r
2301 CLEANUP:\r
2302         // ユーザーオブジェクトの解放\r
2303         if (loggedin_user_object != NULL)\r
2304         {\r
2305                 ReleaseUser(loggedin_user_object);\r
2306         }\r
2307 \r
2308         // エラーパケット送信\r
2309         p = PackError(c->Err);\r
2310         PackAddBool(p, "no_save_password", no_save_password);\r
2311         HttpServerSend(c->FirstSock, p);\r
2312         FreePack(p);\r
2313 \r
2314         SLog(c->Cedar, "LS_CONNECTION_ERROR", c->Name, GetUniErrorStr(c->Err), c->Err);\r
2315 \r
2316         return ret;\r
2317 }\r
2318 // シグネチャの送信 (TCP パケット) 用スレッド\r
2319 void SendSignatureByTcpThread(THREAD *thread, void *param)\r
2320 {\r
2321         BUF *buf;\r
2322         SEND_SIGNATURE_PARAM *p;\r
2323         SOCK *s;\r
2324         // 引数チェック\r
2325         if (thread == NULL || param == NULL)\r
2326         {\r
2327                 return;\r
2328         }\r
2329 \r
2330         p = (SEND_SIGNATURE_PARAM *)param;\r
2331 \r
2332         AddWaitThread(thread);\r
2333         NoticeThreadInit(thread);\r
2334 \r
2335         buf = p->Buffer;\r
2336 \r
2337         s = Connect(p->Hostname, p->Port);\r
2338 \r
2339         if (s != NULL)\r
2340         {\r
2341                 SendAll(s, buf->Buf, buf->Size, false);\r
2342 \r
2343                 Disconnect(s);\r
2344                 ReleaseSock(s);\r
2345         }\r
2346 \r
2347         DelWaitThread(thread);\r
2348 \r
2349         FreeBuf(buf);\r
2350         Free(p);\r
2351 }\r
2352 \r
2353 // シグネチャの送信 (TCP パケット)\r
2354 void SendSignatureByTcp(CONNECTION *c, IP *ip)\r
2355 {\r
2356         NODE_INFO info;\r
2357         BUF *b;\r
2358         SEND_SIGNATURE_PARAM *param;\r
2359         THREAD *t;\r
2360         // 引数チェック\r
2361         if (c == NULL || ip == NULL)\r
2362         {\r
2363                 return;\r
2364         }\r
2365 \r
2366         if (c->Session == NULL || c->Session->ClientOption == NULL)\r
2367         {\r
2368                 return;\r
2369         }\r
2370 \r
2371         CreateNodeInfo(&info, c);\r
2372 \r
2373         b = NewBuf();\r
2374         WriteBuf(b, CEDAR_SIGNATURE_STR, StrLen(CEDAR_SIGNATURE_STR));\r
2375         SeekBuf(b, 0, 0);\r
2376 \r
2377         param = ZeroMalloc(sizeof(SEND_SIGNATURE_PARAM));\r
2378         param->Buffer = b;\r
2379 \r
2380         if (c->Session != NULL && c->Session->ClientOption != NULL)\r
2381         {\r
2382                 CLIENT_OPTION *o = c->Session->ClientOption;\r
2383 \r
2384                 if (o->ProxyType == PROXY_DIRECT)\r
2385                 {\r
2386                         IPToStr(param->Hostname, sizeof(param->Hostname), ip);\r
2387                         param->Port = o->Port;\r
2388                 }\r
2389                 else\r
2390                 {\r
2391                         StrCpy(param->Hostname, sizeof(param->Hostname), o->ProxyName);\r
2392                         param->Port = o->ProxyPort;\r
2393                 }\r
2394         }\r
2395 \r
2396         t = NewThread(SendSignatureByTcpThread, param);\r
2397         WaitThreadInit(t);\r
2398         ReleaseThread(t);\r
2399 }\r
2400 \r
2401 // ノード情報の作成\r
2402 void CreateNodeInfo(NODE_INFO *info, CONNECTION *c)\r
2403 {\r
2404         SESSION *s;\r
2405         OS_INFO *os;\r
2406         char *product_id;\r
2407         IP ip;\r
2408         // 引数チェック\r
2409         if (c == NULL)\r
2410         {\r
2411                 return;\r
2412         }\r
2413 \r
2414         s = c->Session;\r
2415         os = GetOsInfo();\r
2416 \r
2417         Zero(info, sizeof(NODE_INFO));\r
2418 \r
2419         // クライアント製品名\r
2420         StrCpy(info->ClientProductName, sizeof(info->ClientProductName), c->ClientStr);\r
2421         // クライアントバージョン\r
2422         info->ClientProductVer = Endian32(c->ClientVer);\r
2423         // クライアントビルド番号\r
2424         info->ClientProductBuild = Endian32(c->ClientBuild);\r
2425 \r
2426         // サーバー製品名\r
2427         StrCpy(info->ServerProductName, sizeof(info->ServerProductName), c->ServerStr);\r
2428         // サーバーバージョン\r
2429         info->ServerProductVer = Endian32(c->ServerVer);\r
2430         // サーバービルド番号\r
2431         info->ServerProductBuild = Endian32(c->ServerBuild);\r
2432 \r
2433         // クライアント OS 名\r
2434         StrCpy(info->ClientOsName, sizeof(info->ClientOsName), os->OsProductName);\r
2435         // クライアント OS バージョン\r
2436         StrCpy(info->ClientOsVer, sizeof(info->ClientOsVer), os->OsVersion);\r
2437         // クライアント OS プロダクト ID\r
2438         product_id = OSGetProductId();\r
2439         StrCpy(info->ClientOsProductId, sizeof(info->ClientOsProductId), product_id);\r
2440         Free(product_id);\r
2441 \r
2442         // クライアントホスト名\r
2443         GetMachineName(info->ClientHostname, sizeof(info->ClientHostname));\r
2444         // クライアント IP アドレス\r
2445         if (IsIP6(&c->FirstSock->LocalIP) == false)\r
2446         {\r
2447                 info->ClientIpAddress = IPToUINT(&c->FirstSock->LocalIP);\r
2448         }\r
2449         else\r
2450         {\r
2451                 Copy(info->ClientIpAddress6, c->FirstSock->LocalIP.ipv6_addr, sizeof(info->ClientIpAddress6));\r
2452         }\r
2453         // クライアントポート番号\r
2454         info->ClientPort = Endian32(c->FirstSock->LocalPort);\r
2455 \r
2456         // サーバーホスト名\r
2457         StrCpy(info->ServerHostname, sizeof(info->ServerHostname), c->ServerName);\r
2458         // サーバー IP アドレス\r
2459         if (GetIP(&ip, info->ServerHostname))\r
2460         {\r
2461                 if (IsIP6(&ip) == false)\r
2462                 {\r
2463                         info->ServerIpAddress = IPToUINT(&ip);\r
2464                 }\r
2465                 else\r
2466                 {\r
2467                         Copy(info->ServerIpAddress6, ip.ipv6_addr, sizeof(info->ServerIpAddress6));\r
2468                 }\r
2469         }\r
2470         // サーバーポート番号\r
2471         info->ServerPort = Endian32(c->ServerPort);\r
2472 \r
2473         if (s->ClientOption->ProxyType == PROXY_SOCKS || s->ClientOption->ProxyType == PROXY_HTTP)\r
2474         {\r
2475                 // プロキシホスト名\r
2476                 StrCpy(info->ProxyHostname, sizeof(info->ProxyHostname), s->ClientOption->ProxyName);\r
2477 \r
2478                 // プロキシ IP アドレス\r
2479                 if (IsIP6(&c->FirstSock->RemoteIP) == false)\r
2480                 {\r
2481                         info->ProxyIpAddress = IPToUINT(&c->FirstSock->RemoteIP);\r
2482                 }\r
2483                 else\r
2484                 {\r
2485                         Copy(&info->ProxyIpAddress6, c->FirstSock->RemoteIP.ipv6_addr, sizeof(info->ProxyIpAddress6));\r
2486                 }\r
2487 \r
2488                 info->ProxyPort = Endian32(c->FirstSock->RemotePort);\r
2489         }\r
2490 \r
2491         // HUB 名\r
2492         StrCpy(info->HubName, sizeof(info->HubName), s->ClientOption->HubName);\r
2493 \r
2494         // ユニーク ID\r
2495         Copy(info->UniqueId, c->Cedar->UniqueId, sizeof(info->UniqueId));\r
2496 }\r
2497 \r
2498 // ソケットを追加接続する\r
2499 SOCK *ClientAdditionalConnectToServer(CONNECTION *c)\r
2500 {\r
2501         SOCK *s;\r
2502         // 引数チェック\r
2503         if (c == NULL)\r
2504         {\r
2505                 return NULL;\r
2506         }\r
2507 \r
2508         // ソケット接続\r
2509         s = ClientConnectGetSocket(c, true);\r
2510         if (s == NULL)\r
2511         {\r
2512                 // 接続失敗\r
2513                 return NULL;\r
2514         }\r
2515 \r
2516         // ソケットをリストに追加する\r
2517         LockList(c->ConnectingSocks);\r
2518         {\r
2519                 Add(c->ConnectingSocks, s);\r
2520                 AddRef(s->ref);\r
2521         }\r
2522         UnlockList(c->ConnectingSocks);\r
2523 \r
2524         if (c->Session->Halt)\r
2525         {\r
2526                 // 停止\r
2527                 Disconnect(s);\r
2528                 LockList(c->ConnectingSocks);\r
2529                 {\r
2530                         if (Delete(c->ConnectingSocks, s))\r
2531                         {\r
2532                                 ReleaseSock(s);\r
2533                         }\r
2534                 }\r
2535                 UnlockList(c->ConnectingSocks);\r
2536                 ReleaseSock(s);\r
2537                 return NULL;\r
2538         }\r
2539 \r
2540         // タイムアウト\r
2541         SetTimeout(s, CONNECTING_TIMEOUT);\r
2542 \r
2543         // SSL 通信開始\r
2544         if (StartSSLEx(s, NULL, NULL, (c->DontUseTls1 ? false : true)) == false)\r
2545         {\r
2546                 // SSL 通信失敗\r
2547                 Disconnect(s);\r
2548                 LockList(c->ConnectingSocks);\r
2549                 {\r
2550                         if (Delete(c->ConnectingSocks, s))\r
2551                         {\r
2552                                 ReleaseSock(s);\r
2553                         }\r
2554                 }\r
2555                 UnlockList(c->ConnectingSocks);\r
2556                 ReleaseSock(s);\r
2557                 return NULL;\r
2558         }\r
2559 \r
2560         // 証明書のチェック\r
2561         if (CompareX(s->RemoteX, c->ServerX) == false)\r
2562         {\r
2563                 // 証明書が不正\r
2564                 Disconnect(s);\r
2565                 c->Session->SessionTimeOuted = true;\r
2566         }\r
2567 \r
2568         return s;\r
2569 }\r
2570 \r
2571 // セキュアデバイス内の証明書と鍵を削除する\r
2572 UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name)\r
2573 {\r
2574         SECURE *sec;\r
2575         // 引数チェック\r
2576         if (pin == NULL || device_id == 0)\r
2577         {\r
2578                 return ERR_INTERNAL_ERROR;\r
2579         }\r
2580 \r
2581         // デバイスを開く\r
2582         sec = OpenSec(device_id);\r
2583         if (sec == NULL)\r
2584         {\r
2585                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2586         }\r
2587 \r
2588         // セッションを開く\r
2589         if (OpenSecSession(sec, 0) == false)\r
2590         {\r
2591                 CloseSec(sec);\r
2592                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2593         }\r
2594 \r
2595         // ログイン\r
2596         if (LoginSec(sec, pin) == false)\r
2597         {\r
2598                 CloseSecSession(sec);\r
2599                 CloseSec(sec);\r
2600                 return ERR_SECURE_PIN_LOGIN_FAILED;\r
2601         }\r
2602 \r
2603         // 証明書削除\r
2604         if (cert_name != NULL)\r
2605         {\r
2606                 DeleteSecCert(sec, cert_name);\r
2607         }\r
2608 \r
2609         // 秘密鍵削除\r
2610         if (key_name != NULL)\r
2611         {\r
2612                 DeleteSecKey(sec, key_name);\r
2613         }\r
2614 \r
2615         // ログアウト\r
2616         LogoutSec(sec);\r
2617 \r
2618         // セッションを閉じる\r
2619         CloseSecSession(sec);\r
2620 \r
2621         // デバイスを閉じる\r
2622         CloseSec(sec);\r
2623 \r
2624         return ERR_NO_ERROR;\r
2625 }\r
2626 \r
2627 // セキュアデバイス内の証明書と鍵を列挙する\r
2628 UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list)\r
2629 {\r
2630         SECURE *sec;\r
2631         LIST *o;\r
2632         LIST *cert_name_list, *key_name_list;\r
2633         // 引数チェック\r
2634         if (pin == NULL || device_id == 0 || cert_list == NULL || key_list == NULL)\r
2635         {\r
2636                 return ERR_INTERNAL_ERROR;\r
2637         }\r
2638 \r
2639         // デバイスを開く\r
2640         sec = OpenSec(device_id);\r
2641         if (sec == NULL)\r
2642         {\r
2643                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2644         }\r
2645 \r
2646         // セッションを開く\r
2647         if (OpenSecSession(sec, 0) == false)\r
2648         {\r
2649                 CloseSec(sec);\r
2650                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2651         }\r
2652 \r
2653         // ログイン\r
2654         if (LoginSec(sec, pin) == false)\r
2655         {\r
2656                 CloseSecSession(sec);\r
2657                 CloseSec(sec);\r
2658                 return ERR_SECURE_PIN_LOGIN_FAILED;\r
2659         }\r
2660 \r
2661         // オブジェクトの列挙\r
2662         if ((o = EnumSecObject(sec)) != NULL)\r
2663         {\r
2664                 UINT i;\r
2665 \r
2666                 cert_name_list = NewList(CompareStr);\r
2667                 key_name_list = NewList(CompareStr);\r
2668 \r
2669                 for (i = 0;i < LIST_NUM(o);i++)\r
2670                 {\r
2671                         SEC_OBJ *obj = LIST_DATA(o, i);\r
2672 \r
2673                         if (obj->Type == SEC_X)\r
2674                         {\r
2675                                 Add(cert_name_list, CopyStr(obj->Name));\r
2676                         }\r
2677                         else if (obj->Type == SEC_K)\r
2678                         {\r
2679                                 Add(key_name_list, CopyStr(obj->Name));\r
2680                         }\r
2681                 }\r
2682 \r
2683                 Sort(cert_name_list);\r
2684                 Sort(key_name_list);\r
2685 \r
2686                 *cert_list = ListToTokenList(cert_name_list);\r
2687                 *key_list = ListToTokenList(key_name_list);\r
2688 \r
2689                 // メモリ解放\r
2690                 FreeStrList(cert_name_list);\r
2691                 FreeStrList(key_name_list);\r
2692                 FreeEnumSecObject(o);\r
2693         }\r
2694         else\r
2695         {\r
2696                 *cert_list = NullToken();\r
2697                 *key_list = NullToken();\r
2698         }\r
2699 \r
2700         // ログアウト\r
2701         LogoutSec(sec);\r
2702 \r
2703         // セッションを閉じる\r
2704         CloseSecSession(sec);\r
2705 \r
2706         // デバイスを閉じる\r
2707         CloseSec(sec);\r
2708 \r
2709         return ERR_NO_ERROR;\r
2710 }\r
2711 \r
2712 // セキュアデバイスに証明書と鍵を記録する\r
2713 UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin)\r
2714 {\r
2715         SECURE *sec;\r
2716         bool failed;\r
2717         // 引数チェック\r
2718         if (pin == NULL || device_id == 0 || cert_name == NULL || x == NULL || key_name == NULL || k == NULL)\r
2719         {\r
2720                 return ERR_INTERNAL_ERROR;\r
2721         }\r
2722 \r
2723         // デバイスを開く\r
2724         sec = OpenSec(device_id);\r
2725         if (sec == NULL)\r
2726         {\r
2727                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2728         }\r
2729 \r
2730         // セッションを開く\r
2731         if (OpenSecSession(sec, 0) == false)\r
2732         {\r
2733                 CloseSec(sec);\r
2734                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2735         }\r
2736 \r
2737         // ログイン\r
2738         if (LoginSec(sec, pin) == false)\r
2739         {\r
2740                 CloseSecSession(sec);\r
2741                 CloseSec(sec);\r
2742                 return ERR_SECURE_PIN_LOGIN_FAILED;\r
2743         }\r
2744 \r
2745         // 登録\r
2746         failed = false;\r
2747 \r
2748         // 証明書の登録\r
2749         if (WriteSecCert(sec, true, cert_name, x) == false)\r
2750         {\r
2751                 failed = true;\r
2752         }\r
2753 \r
2754         // 秘密鍵の登録\r
2755         if (WriteSecKey(sec, true, key_name, k) == false)\r
2756         {\r
2757                 failed = true;\r
2758         }\r
2759 \r
2760         // ログアウト\r
2761         LogoutSec(sec);\r
2762 \r
2763         // セッションを閉じる\r
2764         CloseSecSession(sec);\r
2765 \r
2766         // デバイスを閉じる\r
2767         CloseSec(sec);\r
2768 \r
2769         if (failed == false)\r
2770         {\r
2771                 // 成功\r
2772                 return ERR_NO_ERROR;\r
2773         }\r
2774         else\r
2775         {\r
2776                 // 失敗\r
2777                 return ERR_SECURE_CANT_WRITE;\r
2778         }\r
2779 }\r
2780 \r
2781 // セキュアデバイスによる署名を試行する\r
2782 UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin)\r
2783 {\r
2784         SECURE *sec;\r
2785         X *x;\r
2786         // 引数チェック\r
2787         if (sign == false || pin == NULL || device_id == 0)\r
2788         {\r
2789                 return ERR_INTERNAL_ERROR;\r
2790         }\r
2791 \r
2792         // デバイスを開く\r
2793         sec = OpenSec(device_id);\r
2794         if (sec == NULL)\r
2795         {\r
2796                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2797         }\r
2798 \r
2799         // セッションを開く\r
2800         if (OpenSecSession(sec, 0) == false)\r
2801         {\r
2802                 CloseSec(sec);\r
2803                 return ERR_SECURE_DEVICE_OPEN_FAILED;\r
2804         }\r
2805 \r
2806         // ログイン\r
2807         if (LoginSec(sec, pin) == false)\r
2808         {\r
2809                 CloseSecSession(sec);\r
2810                 CloseSec(sec);\r
2811                 return ERR_SECURE_PIN_LOGIN_FAILED;\r
2812         }\r
2813 \r
2814         // 証明書の読み込み\r
2815         x = ReadSecCert(sec, sign->SecurePublicCertName);\r
2816         if (x == NULL)\r
2817         {\r
2818                 LogoutSec(sec);\r
2819                 CloseSecSession(sec);\r
2820                 CloseSec(sec);\r
2821                 return ERR_SECURE_NO_CERT;\r
2822         }\r
2823 \r
2824         // 秘密鍵による署名\r
2825         if (SignSec(sec, sign->SecurePrivateKeyName, sign->Signature, sign->Random, SHA1_SIZE) == false)\r
2826         {\r
2827                 // 署名失敗\r
2828                 FreeX(x);\r
2829                 LogoutSec(sec);\r
2830                 CloseSecSession(sec);\r
2831                 CloseSec(sec);\r
2832                 return ERR_SECURE_NO_PRIVATE_KEY;\r
2833         }\r
2834 \r
2835         // 証明書をバッファに変換\r
2836         sign->ClientCert = x;\r
2837 \r
2838         // ログアウト\r
2839         LogoutSec(sec);\r
2840 \r
2841         // セッションを閉じる\r
2842         CloseSecSession(sec);\r
2843 \r
2844         // デバイスを閉じる\r
2845         CloseSec(sec);\r
2846 \r
2847         // 成功\r
2848         return ERR_NO_ERROR;\r
2849 }\r
2850 \r
2851 // クライアントがサーバーに追加接続する\r
2852 bool ClientAdditionalConnect(CONNECTION *c, THREAD *t)\r
2853 {\r
2854         SOCK *s;\r
2855         PACK *p;\r
2856         TCPSOCK *ts;\r
2857         UINT err;\r
2858         UINT direction;\r
2859         RC4_KEY_PAIR key_pair;\r
2860         // 引数チェック\r
2861         if (c == NULL)\r
2862         {\r
2863                 return false;\r
2864         }\r
2865 \r
2866         // サーバーにソケット接続\r
2867         s = ClientAdditionalConnectToServer(c);\r
2868         if (s == NULL)\r
2869         {\r
2870                 // ソケット接続に失敗\r
2871                 return false;\r
2872         }\r
2873 \r
2874         if (c->Halt)\r
2875         {\r
2876                 goto CLEANUP;\r
2877         }\r
2878 \r
2879         // シグネチャを送信\r
2880         Debug("Uploading Signature...\n");\r
2881         if (ClientUploadSignature(s) == false)\r
2882         {\r
2883                 goto CLEANUP;\r
2884         }\r
2885 \r
2886         if (c->Halt)\r
2887         {\r
2888                 // 停止\r
2889                 goto CLEANUP;\r
2890         }\r
2891 \r
2892         // Hello パケットを受信\r
2893         Debug("Downloading Hello...\n");\r
2894         if (ClientDownloadHello(c, s) == false)\r
2895         {\r
2896                 goto CLEANUP;\r
2897         }\r
2898 \r
2899         if (c->Halt)\r
2900         {\r
2901                 // 停止\r
2902                 goto CLEANUP;\r
2903         }\r
2904 \r
2905         // 追加接続用の認証データを送信\r
2906         if (ClientUploadAuth2(c, s) == false)\r
2907         {\r
2908                 // 切断された\r
2909                 goto CLEANUP;\r
2910         }\r
2911 \r
2912         // 応答を受信\r
2913         p = HttpClientRecv(s);\r
2914         if (p == NULL)\r
2915         {\r
2916                 // 切断された\r
2917                 goto CLEANUP;\r
2918         }\r
2919 \r
2920         err = GetErrorFromPack(p);\r
2921         direction = PackGetInt(p, "direction");\r
2922 \r
2923         if (c->Session->UseFastRC4)\r
2924         {\r
2925                 // RC4 鍵情報の取得\r
2926                 if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)\r
2927                 {\r
2928                         PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);\r
2929                 }\r
2930                 if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)\r
2931                 {\r
2932                         PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);\r
2933                 }\r
2934                 {\r
2935                         char key1[64], key2[64];\r
2936                         BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);\r
2937                         BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);\r
2938                         Debug(\r
2939                                 "Client to Server Key: %s\n"\r
2940                                 "Server to Client Key: %s\n",\r
2941                                 key1, key2);\r
2942                 }\r
2943         }\r
2944 \r
2945         FreePack(p);\r
2946         p = NULL;\r
2947 \r
2948         if (err != 0)\r
2949         {\r
2950                 // エラーが発生した\r
2951                 Debug("Additional Connect Error: %u\n", err);\r
2952                 if (err == ERR_SESSION_TIMEOUT || err == ERR_INVALID_PROTOCOL)\r
2953                 {\r
2954                         // 致命的なエラーなので再接続しなおすことにする\r
2955                         c->Session->SessionTimeOuted = true;\r
2956                 }\r
2957                 goto CLEANUP;\r
2958         }\r
2959 \r
2960         Debug("Additional Connect Succeed!\n");\r
2961 \r
2962         // 追加接続成功\r
2963         // コネクションの TcpSockList に追加する\r
2964         ts = NewTcpSock(s);\r
2965 \r
2966         if (c->ServerMode == false)\r
2967         {\r
2968                 if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)\r
2969                 {\r
2970                         ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;\r
2971                 }\r
2972         }\r
2973 \r
2974         LockList(c->Tcp->TcpSockList);\r
2975         {\r
2976                 ts->Direction = direction;\r
2977                 Add(c->Tcp->TcpSockList, ts);\r
2978         }\r
2979         UnlockList(c->Tcp->TcpSockList);\r
2980         Debug("TCP Connection Incremented: %u\n", Count(c->CurrentNumConnection));\r
2981 \r
2982         if (c->Session->HalfConnection)\r
2983         {\r
2984                 Debug("New Half Connection: %s\n",\r
2985                         direction == TCP_SERVER_TO_CLIENT ? "TCP_SERVER_TO_CLIENT" : "TCP_CLIENT_TO_SERVER"\r
2986                         );\r
2987         }\r
2988 \r
2989         if (c->Session->UseFastRC4)\r
2990         {\r
2991                 // RC4 暗号化鍵のセット\r
2992                 Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));\r
2993 \r
2994                 InitTcpSockRc4Key(ts, false);\r
2995         }\r
2996 \r
2997         // セッションに Cancel を発行する\r
2998         Cancel(c->Session->Cancel1);\r
2999 \r
3000         // 接続中のソケット一覧からこのソケットを削除\r
3001         LockList(c->ConnectingSocks);\r
3002         {\r
3003                 if (Delete(c->ConnectingSocks, s))\r
3004                 {\r
3005                         ReleaseSock(s);\r
3006                 }\r
3007         }\r
3008         UnlockList(c->ConnectingSocks);\r
3009         ReleaseSock(s);\r
3010         return true;\r
3011 \r
3012 CLEANUP:\r
3013         // 切断処理\r
3014         Disconnect(s);\r
3015         LockList(c->ConnectingSocks);\r
3016         {\r
3017                 if (Delete(c->ConnectingSocks, s))\r
3018                 {\r
3019                         ReleaseSock(s);\r
3020 \r
3021                 }\r
3022         }\r
3023         UnlockList(c->ConnectingSocks);\r
3024         ReleaseSock(s);\r
3025         return false;\r
3026 }\r
3027 \r
3028 // セキュアデバイス署名スレッド\r
3029 void ClientSecureSignThread(THREAD *thread, void *param)\r
3030 {\r
3031         SECURE_SIGN_THREAD_PROC *p = (SECURE_SIGN_THREAD_PROC *)param;\r
3032         // 引数チェック\r
3033         if (thread == NULL || param == NULL)\r
3034         {\r
3035                 return;\r
3036         }\r
3037 \r
3038         NoticeThreadInit(thread);\r
3039 \r
3040         p->Ok = p->SecureSignProc(p->Connection->Session, p->Connection, p->SecureSign);\r
3041         p->UserFinished = true;\r
3042 }\r
3043 \r
3044 // セキュアデバイスを使用した署名\r
3045 bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x)\r
3046 {\r
3047         SECURE_SIGN_THREAD_PROC *p;\r
3048         SECURE_SIGN *ss;\r
3049         SESSION *s;\r
3050         CLIENT_OPTION *o;\r
3051         CLIENT_AUTH *a;\r
3052         THREAD *thread;\r
3053         UINT64 start;\r
3054         bool ret;\r
3055         // 引数チェック\r
3056         if (c == NULL || sign == NULL || random == NULL || x == NULL)\r
3057         {\r
3058                 return false;\r
3059         }\r
3060 \r
3061         s = c->Session;\r
3062         o = s->ClientOption;\r
3063         a = s->ClientAuth;\r
3064 \r
3065         p = ZeroMalloc(sizeof(SECURE_SIGN_THREAD_PROC));\r
3066         p->Connection = c;\r
3067         ss = p->SecureSign = ZeroMallocEx(sizeof(SECURE_SIGN), true);\r
3068         StrCpy(ss->SecurePrivateKeyName, sizeof(ss->SecurePrivateKeyName),\r
3069                 a->SecurePrivateKeyName);\r
3070         StrCpy(ss->SecurePublicCertName, sizeof(ss->SecurePublicCertName),\r
3071                 a->SecurePublicCertName);\r
3072         ss->UseSecureDeviceId = c->Cedar->Client->UseSecureDeviceId;\r
3073         Copy(ss->Random, random, SHA1_SIZE);\r
3074 \r
3075 #ifdef  OS_WIN32\r
3076         ss->BitmapId = CmGetSecureBitmapId(c->ServerName);\r
3077 #endif  // OS_WIN32\r
3078 \r
3079         p->SecureSignProc = a->SecureSignProc;\r
3080 \r
3081         // スレッド作成\r
3082         thread = NewThread(ClientSecureSignThread, p);\r
3083         WaitThreadInit(thread);\r
3084 \r
3085         // 署名が完了するかキャンセルするまで 0.5 秒ごとにポーリングする\r
3086         start = Tick64();\r
3087         while (true)\r
3088         {\r
3089                 if ((Tick64() - start) > CONNECTING_POOLING_SPAN)\r
3090                 {\r
3091                         // 切断防止のため一定期間ごとに NOOP を送信する\r
3092                         start = Tick64();\r
3093                         ClientUploadNoop(c);\r
3094                 }\r
3095                 if (p->UserFinished)\r
3096                 {\r
3097                         // ユーザーが選択した\r
3098                         break;\r
3099                 }\r
3100                 WaitThread(thread, 500);\r
3101         }\r
3102         ReleaseThread(thread);\r
3103 \r
3104         ret = p->Ok;\r
3105 \r
3106         if (ret)\r
3107         {\r
3108                 Copy(sign, ss->Signature, 128);\r
3109                 *x = ss->ClientCert;\r
3110         }\r
3111 \r
3112         Free(p->SecureSign);\r
3113         Free(p);\r
3114 \r
3115         return ret;\r
3116 }\r
3117 \r
3118 // サーバー証明書確認用スレッド\r
3119 void ClientCheckServerCertThread(THREAD *thread, void *param)\r
3120 {\r
3121         CHECK_CERT_THREAD_PROC *p = (CHECK_CERT_THREAD_PROC *)param;\r
3122         // 引数チェック\r
3123         if (thread == NULL || param == NULL)\r
3124         {\r
3125                 return;\r
3126         }\r
3127 \r
3128         // 初期化完了を通知する\r
3129         NoticeThreadInit(thread);\r
3130 \r
3131         // ユーザーに選択を問い合わせる\r
3132         p->Ok = p->CheckCertProc(p->Connection->Session, p->Connection, p->ServerX, &p->Exipred);\r
3133         p->UserSelected = true;\r
3134 }\r
3135 \r
3136 // クライアントがサーバーの証明書を確認する\r
3137 bool ClientCheckServerCert(CONNECTION *c, bool *expired)\r
3138 {\r
3139         CLIENT_AUTH *auth;\r
3140         X *x;\r
3141         CHECK_CERT_THREAD_PROC *p;\r
3142         THREAD *thread;\r
3143         CEDAR *cedar;\r
3144         bool ret;\r
3145         UINT64 start;\r
3146         // 引数チェック\r
3147         if (c == NULL)\r
3148         {\r
3149                 return false;\r
3150         }\r
3151 \r
3152         if (expired != NULL)\r
3153         {\r
3154                 *expired = false;\r
3155         }\r
3156 \r
3157         auth = c->Session->ClientAuth;\r
3158         cedar = c->Cedar;\r
3159 \r
3160         if (auth->CheckCertProc == NULL && c->Session->LinkModeClient == false)\r
3161         {\r
3162                 // チェック関数無し\r
3163                 return true;\r
3164         }\r
3165 \r
3166         if (c->Session->LinkModeClient && c->Session->Link->CheckServerCert == false)\r
3167         {\r
3168                 // カスケード接続モードだがサーバー証明書はチェックしない\r
3169                 return true;\r
3170         }\r
3171 \r
3172         if (c->UseTicket)\r
3173         {\r
3174                 // リダイレクト先 VPN サーバーの証明書を確認する\r
3175                 if (CompareX(c->FirstSock->RemoteX, c->ServerX) == false)\r
3176                 {\r
3177                         return false;\r
3178                 }\r
3179                 else\r
3180                 {\r
3181                         return true;\r
3182                 }\r
3183         }\r
3184 \r
3185         x = CloneX(c->FirstSock->RemoteX);\r
3186         if (x == NULL)\r
3187         {\r
3188                 // 変なエラーが発生した\r
3189                 return false;\r
3190         }\r
3191 \r
3192         if (CheckXDateNow(x))\r
3193         {\r
3194                 // 信頼するルート証明書によって署名されているかどうか確認する\r
3195                 if (c->Session->LinkModeClient == false)\r
3196                 {\r
3197                         // 通常の VPN Client モード\r
3198                         if (CheckSignatureByCa(cedar, x))\r
3199                         {\r
3200                                 // 署名されているのでこの証明書は信頼できる\r
3201                                 FreeX(x);\r
3202                                 return true;\r
3203                         }\r
3204                 }\r
3205                 else\r
3206                 {\r
3207                         // カスケード接続モード\r
3208                         if (CheckSignatureByCaLinkMode(c->Session, x))\r
3209                         {\r
3210                                 // 署名されているのでこの証明書は信頼できる\r
3211                                 FreeX(x);\r
3212                                 return true;\r
3213                         }\r
3214                 }\r
3215         }\r
3216 \r
3217         if (c->Session->LinkModeClient)\r
3218         {\r
3219                 if (CheckXDateNow(x))\r
3220                 {\r
3221                         Lock(c->Session->Link->lock);\r
3222                         {\r
3223                                 if (c->Session->Link->ServerCert != NULL)\r
3224                                 {\r
3225                                         if (CompareX(c->Session->Link->ServerCert, x))\r
3226                                         {\r
3227                                                 Unlock(c->Session->Link->lock);\r
3228                                                 // カスケード接続設定に登録されている証明書と完全一致\r
3229                                                 FreeX(x);\r
3230                                                 return true;\r
3231                                         }\r
3232                                 }\r
3233                         }\r
3234                         Unlock(c->Session->Link->lock);\r
3235                 }\r
3236                 else\r
3237                 {\r
3238                         if (expired != NULL)\r
3239                         {\r
3240                                 *expired = true;\r
3241                         }\r
3242                 }\r
3243 \r
3244                 // カスケード接続モードの場合はこの時点で検証失敗\r
3245                 FreeX(x);\r
3246                 return false;\r
3247         }\r
3248 \r
3249         p = ZeroMalloc(sizeof(CHECK_CERT_THREAD_PROC));\r
3250         p->ServerX = x;\r
3251         p->CheckCertProc = auth->CheckCertProc;\r
3252         p->Connection = c;\r
3253 \r
3254         // スレッドを作成する\r
3255         thread = NewThread(ClientCheckServerCertThread, p);\r
3256         WaitThreadInit(thread);\r
3257 \r
3258         // ユーザーが接続の可否を選択するまで 0.5 秒間隔でポーリングする\r
3259         start = Tick64();\r
3260         while (true)\r
3261         {\r
3262                 if ((Tick64() - start) > CONNECTING_POOLING_SPAN)\r
3263                 {\r
3264                         // 切断防止のため一定期間ごとに NOOP を送信する\r
3265                         start = Tick64();\r
3266                         ClientUploadNoop(c);\r
3267                 }\r
3268                 if (p->UserSelected)\r
3269                 {\r
3270                         // ユーザーが選択した\r
3271                         break;\r
3272                 }\r
3273                 WaitThread(thread, 500);\r
3274         }\r
3275 \r
3276         if (expired != NULL)\r
3277         {\r
3278                 *expired = p->Exipred;\r
3279         }\r
3280 \r
3281         ret = p->Ok;\r
3282         FreeX(p->ServerX);\r
3283         Free(p);\r
3284         ReleaseThread(thread);\r
3285 \r
3286         return ret;\r
3287 }\r
3288 \r
3289 // クライアントがサーバーに接続する\r
3290 bool ClientConnect(CONNECTION *c)\r
3291 {\r
3292         bool ret = false;\r
3293         bool ok = false;\r
3294         UINT err;\r
3295         SOCK *s;\r
3296         PACK *p = NULL;\r
3297         UINT session_key_32;\r
3298         SESSION *sess;\r
3299         char session_name[MAX_SESSION_NAME_LEN + 1];\r
3300         char connection_name[MAX_CONNECTION_NAME_LEN + 1];\r
3301         UCHAR session_key[SHA1_SIZE];\r
3302         RC4_KEY_PAIR key_pair;\r
3303         POLICY *policy;\r
3304         bool expired = false;\r
3305         IP server_ip;\r
3306         // 引数チェック\r
3307         if (c == NULL)\r
3308         {\r
3309                 return false;\r
3310         }\r
3311 \r
3312         sess = c->Session;\r
3313 \r
3314         PrintStatus(sess, L"init");\r
3315         PrintStatus(sess, _UU("STATUS_1"));\r
3316 \r
3317 REDIRECTED:\r
3318 \r
3319         // [接続中]\r
3320         c->Status = CONNECTION_STATUS_CONNECTING;\r
3321         c->Session->ClientStatus = CLIENT_STATUS_CONNECTING;\r
3322 \r
3323         s = ClientConnectToServer(c);\r
3324         if (s == NULL)\r
3325         {\r
3326                 PrintStatus(sess, L"free");\r
3327                 return false;\r
3328         }\r
3329 \r
3330         Copy(&server_ip, &s->RemoteIP, sizeof(IP));\r
3331 \r
3332         if (c->Halt)\r
3333         {\r
3334                 // 停止\r
3335                 c->Err = ERR_USER_CANCEL;\r
3336                 goto CLEANUP;\r
3337         }\r
3338 \r
3339         // [ネゴシエーション中]\r
3340         c->Session->ClientStatus = CLIENT_STATUS_NEGOTIATION;\r
3341 \r
3342         // シグネチャを送信\r
3343         Debug("Uploading Signature...\n");\r
3344         if (ClientUploadSignature(s) == false)\r
3345         {\r
3346                 c->Err = ERR_DISCONNECTED;\r
3347                 goto CLEANUP;\r
3348         }\r
3349 \r
3350         if (c->Halt)\r
3351         {\r
3352                 // 停止\r
3353                 c->Err = ERR_USER_CANCEL;\r
3354                 goto CLEANUP;\r
3355         }\r
3356 \r
3357         PrintStatus(sess, _UU("STATUS_5"));\r
3358 \r
3359         // Hello パケットを受信\r
3360         Debug("Downloading Hello...\n");\r
3361         if (ClientDownloadHello(c, s) == false)\r
3362         {\r
3363                 goto CLEANUP;\r
3364         }\r
3365 \r
3366         if (c->Session->ClientOption != NULL && c->Session->ClientOption->FromAdminPack)\r
3367         {\r
3368                 if (IsAdminPackSupportedServerProduct(c->ServerStr) == false)\r
3369                 {\r
3370                         c->Err = ERR_NOT_ADMINPACK_SERVER;\r
3371                         goto CLEANUP;\r
3372                 }\r
3373         }\r
3374 \r
3375         if (c->Halt)\r
3376         {\r
3377                 // 停止\r
3378                 c->Err = ERR_USER_CANCEL;\r
3379                 goto CLEANUP;\r
3380         }\r
3381 \r
3382         Debug("Server Version : %u\n"\r
3383                 "Server String  : %s\n"\r
3384                 "Server Build   : %u\n"\r
3385                 "Client Version : %u\n"\r
3386                 "Client String  : %s\n"\r
3387                 "Client Build   : %u\n",\r
3388                 c->ServerVer, c->ServerStr, c->ServerBuild,\r
3389                 c->ClientVer, c->ClientStr, c->ClientBuild);\r
3390 \r
3391         // ユーザー認証中\r
3392         c->Session->ClientStatus = CLIENT_STATUS_AUTH;\r
3393 \r
3394         // クライアントによるサーバー証明書の確認\r
3395         if (ClientCheckServerCert(c, &expired) == false)\r
3396         {\r
3397                 if (expired == false)\r
3398                 {\r
3399                         c->Err = ERR_CERT_NOT_TRUSTED;\r
3400                 }\r
3401                 else\r
3402                 {\r
3403                         c->Err = ERR_SERVER_CERT_EXPIRES;\r
3404                 }\r
3405 \r
3406                 if (c->Session->LinkModeClient == false && c->Err == ERR_CERT_NOT_TRUSTED)\r
3407                 {\r
3408                         c->Session->ForceStopFlag = true;\r
3409                 }\r
3410 \r
3411                 goto CLEANUP;\r
3412         }\r
3413 \r
3414         PrintStatus(sess, _UU("STATUS_6"));\r
3415 \r
3416         // 認証データを送信\r
3417         if (ClientUploadAuth(c) == false)\r
3418         {\r
3419                 goto CLEANUP;\r
3420         }\r
3421 \r
3422         if (c->Halt)\r
3423         {\r
3424                 // 停止\r
3425                 c->Err = ERR_USER_CANCEL;\r
3426                 goto CLEANUP;\r
3427         }\r
3428 \r
3429         // Welcome パケットを受信\r
3430         p = HttpClientRecv(s);\r
3431         if (p == NULL)\r
3432         {\r
3433                 c->Err = ERR_DISCONNECTED;\r
3434                 goto CLEANUP;\r
3435         }\r
3436 \r
3437         // エラーチェック\r
3438         err = GetErrorFromPack(p);\r
3439         if (err != 0)\r
3440         {\r
3441                 // エラー発生\r
3442                 c->Err = err;\r
3443                 c->ClientConnectError_NoSavePassword = PackGetBool(p, "no_save_password");\r
3444                 goto CLEANUP;\r
3445         }\r
3446 \r
3447         // 接続制限のためのブランド化文字列チェック\r
3448         {\r
3449                 char tmp[20];\r
3450                 char *branded_cfroms = _SS("BRANDED_C_FROM_S");\r
3451                 PackGetStr(p, "branded_cfroms", tmp, sizeof(tmp));\r
3452 \r
3453                 if(StrLen(branded_cfroms) > 0 && StrCmpi(branded_cfroms, tmp) != 0)\r
3454                 {\r
3455                         c->Err = ERR_BRANDED_C_FROM_S;\r
3456                         goto CLEANUP;\r
3457                 }\r
3458         }\r
3459 \r
3460         if (true)\r
3461         {\r
3462                 // メッセージ取得\r
3463                 UINT utf_size;\r
3464                 char *utf;\r
3465                 wchar_t *msg;\r
3466 \r
3467                 utf_size = PackGetDataSize(p, "Msg");\r
3468                 utf = ZeroMalloc(utf_size + 8);\r
3469                 PackGetData(p, "Msg", utf);\r
3470 \r
3471                 msg = CopyUtfToUni(utf);\r
3472 \r
3473                 if (IsEmptyUniStr(msg) == false)\r
3474                 {\r
3475                         if (c->Session->Client_Message != NULL)\r
3476                         {\r
3477                                 Free(c->Session->Client_Message);\r
3478                         }\r
3479 \r
3480                         c->Session->Client_Message = msg;\r
3481                 }\r
3482                 else\r
3483                 {\r
3484                         Free(msg);\r
3485                 }\r
3486 \r
3487                 Free(utf);\r
3488         }\r
3489 \r
3490         if (PackGetInt(p, "Redirect") != 0)\r
3491         {\r
3492                 UINT i;\r
3493                 UINT ip;\r
3494                 UINT num_port;\r
3495                 UINT *ports;\r
3496                 UINT use_port = 0;\r
3497                 UINT current_port = c->ServerPort;\r
3498                 UCHAR ticket[SHA1_SIZE];\r
3499                 X *server_cert;\r
3500                 BUF *b;\r
3501 \r
3502                 // リダイレクトモード\r
3503                 PrintStatus(sess, _UU("STATUS_8"));\r
3504 \r
3505                 ip = PackGetIp32(p, "Ip");\r
3506                 num_port = MAX(MIN(PackGetIndexCount(p, "Port"), MAX_PUBLIC_PORT_NUM), 1);\r
3507                 ports = ZeroMalloc(sizeof(UINT) * num_port);\r
3508                 for (i = 0;i < num_port;i++)\r
3509                 {\r
3510                         ports[i] = PackGetIntEx(p, "Port", i);\r
3511                 }\r
3512 \r
3513                 // ポート番号を選定する\r
3514                 for (i = 0;i < num_port;i++)\r
3515                 {\r
3516                         if (ports[i] == current_port)\r
3517                         {\r
3518                                 use_port = current_port;\r
3519                         }\r
3520                 }\r
3521                 if (use_port == 0)\r
3522                 {\r
3523                         use_port = ports[0];\r
3524                 }\r
3525 \r
3526                 Free(ports);\r
3527 \r
3528                 if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)\r
3529                 {\r
3530                         PackGetData(p, "Ticket", ticket);\r
3531                 }\r
3532 \r
3533                 b = PackGetBuf(p, "Cert");\r
3534                 if (b != NULL)\r
3535                 {\r
3536                         server_cert = BufToX(b, false);\r
3537                         FreeBuf(b);\r
3538                 }\r
3539 \r
3540                 if (c->ServerX != NULL)\r
3541                 {\r
3542                         FreeX(c->ServerX);\r
3543                 }\r
3544                 c->ServerX = server_cert;\r
3545 \r
3546                 IPToStr32(c->ServerName, sizeof(c->ServerName), ip);\r
3547                 c->ServerPort = use_port;\r
3548 \r
3549                 c->UseTicket = true;\r
3550                 Copy(c->Ticket, ticket, SHA1_SIZE);\r
3551 \r
3552                 FreePack(p);\r
3553 \r
3554                 p = NewPack();\r
3555                 HttpClientSend(s, p);\r
3556                 FreePack(p);\r
3557 \r
3558                 p = NULL;\r
3559 \r
3560                 c->FirstSock = NULL;\r
3561                 Disconnect(s);\r
3562                 ReleaseSock(s);\r
3563                 s = NULL;\r
3564 \r
3565                 goto REDIRECTED;\r
3566         }\r
3567 \r
3568         PrintStatus(sess, _UU("STATUS_7"));\r
3569 \r
3570         // Welcome パケットをパース\r
3571         if (ParseWelcomeFromPack(p, session_name, sizeof(session_name),\r
3572                 connection_name, sizeof(connection_name), &policy) == false)\r
3573         {\r
3574                 // パース失敗\r
3575                 c->Err = ERR_PROTOCOL_ERROR;\r
3576                 goto CLEANUP;\r
3577         }\r
3578 \r
3579         // セッションキーを取得\r
3580         if (GetSessionKeyFromPack(p, session_key, &session_key_32) == false)\r
3581         {\r
3582                 // 取得失敗\r
3583                 Free(policy);\r
3584                 policy = NULL;\r
3585                 c->Err = ERR_PROTOCOL_ERROR;\r
3586                 goto CLEANUP;\r
3587         }\r
3588 \r
3589         Copy(c->Session->SessionKey, session_key, SHA1_SIZE);\r
3590         c->Session->SessionKey32 = session_key_32;\r
3591 \r
3592         // Welcome パケットの内容を保存\r
3593         Debug("session_name: %s, connection_name: %s\n",\r
3594                 session_name, connection_name);\r
3595 \r
3596         Lock(c->Session->lock);\r
3597         {\r
3598                 // 接続パラメータの展開と更新\r
3599                 c->Session->MaxConnection = PackGetInt(p, "max_connection");\r
3600                 c->Session->MaxConnection = MIN(c->Session->MaxConnection, c->Session->ClientOption->MaxConnection);\r
3601                 c->Session->MaxConnection = MIN(c->Session->MaxConnection, MAX_TCP_CONNECTION);\r
3602                 c->Session->MaxConnection = MAX(c->Session->MaxConnection, 1);\r
3603                 c->Session->UseCompress = PackGetInt(p, "use_compress") == 0 ? false : true;\r
3604                 c->Session->UseEncrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;\r
3605                 c->Session->NoSendSignature = PackGetBool(p, "no_send_signature");\r
3606                 if (c->Session->UseEncrypt)\r
3607                 {\r
3608                         c->Session->UseFastRC4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;\r
3609                 }\r
3610                 c->Session->HalfConnection = PackGetInt(p, "half_connection") == 0 ? false : true;\r
3611                 c->Session->Timeout = PackGetInt(p, "timeout");\r
3612                 c->Session->QoS = PackGetInt(p, "qos") == 0 ? false : true;\r
3613                 if (c->Session->QoS)\r
3614                 {\r
3615                         c->Session->MaxConnection = MAX(c->Session->MaxConnection, (UINT)(c->Session->HalfConnection ? 4 : 2));\r
3616                 }\r
3617                 c->Session->VLanId = PackGetInt(p, "vlan_id");\r
3618 \r
3619                 if (c->Protocol == CONNECTION_UDP)\r
3620                 {\r
3621                         // UDP プロトコルの場合、サーバーから鍵を受け取る\r
3622                         if (PackGetDataSize(p, "udp_send_key") == sizeof(c->Session->UdpSendKey))\r
3623                         {\r
3624                                 PackGetData(p, "udp_send_key", c->Session->UdpSendKey);\r
3625                         }\r
3626 \r
3627                         if (PackGetDataSize(p, "udp_recv_key") == sizeof(c->Session->UdpRecvKey))\r
3628                         {\r
3629                                 PackGetData(p, "udp_recv_key", c->Session->UdpRecvKey);\r
3630                         }\r
3631                 }\r
3632 \r
3633                 if (c->Session->UseFastRC4)\r
3634                 {\r
3635                         // RC4 鍵情報の取得\r
3636                         if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)\r
3637                         {\r
3638                                 PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);\r
3639                         }\r
3640                         if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)\r
3641                         {\r
3642                                 PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);\r
3643                         }\r
3644                         {\r
3645                                 char key1[64], key2[64];\r
3646                                 BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);\r
3647                                 BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);\r
3648                                 Debug(\r
3649                                         "Client to Server Key: %s\n"\r
3650                                         "Server to Client Key: %s\n",\r
3651                                         key1, key2);\r
3652                         }\r
3653                 }\r
3654         }\r
3655         Unlock(c->Session->lock);\r
3656 \r
3657         Lock(c->lock);\r
3658         {\r
3659                 if (c->Name != NULL)\r
3660                 {\r
3661                         Free(c->Name);\r
3662                 }\r
3663                 c->Name = CopyStr(connection_name);\r
3664 \r
3665                 // 暗号化アルゴリズム名の保存\r
3666                 if (c->CipherName != NULL)\r
3667                 {\r
3668                         Free(c->CipherName);\r
3669                 }\r
3670 \r
3671                 c->CipherName = CopyStr(c->FirstSock->CipherName);\r
3672         }\r
3673         Unlock(c->lock);\r
3674 \r
3675         Lock(c->Session->lock);\r
3676         {\r
3677                 if (c->Session->Name != NULL)\r
3678                 {\r
3679                         Free(c->Session->Name);\r
3680                 }\r
3681                 c->Session->Name = CopyStr(session_name);\r
3682 \r
3683                 c->Session->Policy = policy;\r
3684         }\r
3685         Unlock(c->Session->lock);\r
3686 \r
3687         // Welcome パケットを破棄\r
3688         FreePack(p);\r
3689         p = NULL;\r
3690 \r
3691         // server_ip に対して TCP でシグネチャを送信\r
3692         if (c->Session->NoSendSignature == false)\r
3693         {\r
3694                 SendSignatureByTcp(c, &server_ip);\r
3695         }\r
3696 \r
3697         // コネクション確立\r
3698         c->Session->ClientStatus = CLIENT_STATUS_ESTABLISHED;\r
3699 \r
3700         // サーバー証明書の保存\r
3701         if (c->ServerX == NULL)\r
3702         {\r
3703                 c->ServerX = CloneX(c->FirstSock->RemoteX);\r
3704         }\r
3705 \r
3706         PrintStatus(sess, _UU("STATUS_9"));\r
3707 \r
3708         // コネクションをトンネリングモードに移行\r
3709         StartTunnelingMode(c);\r
3710         s = NULL;\r
3711 \r
3712         if (c->Session->HalfConnection)\r
3713         {\r
3714                 // ハーフコネクション時の処理\r
3715                 TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);\r
3716                 ts->Direction = TCP_CLIENT_TO_SERVER;\r
3717         }\r
3718 \r
3719         if (c->Session->UseFastRC4)\r
3720         {\r
3721                 // RC4 高速暗号化鍵のセット\r
3722                 TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);\r
3723                 Copy(&ts->Rc4KeyPair, &key_pair, sizeof(key_pair));\r
3724 \r
3725                 InitTcpSockRc4Key(ts, false);\r
3726         }\r
3727 \r
3728         // SSL 暗号化フラグ\r
3729         if (c->Session->UseEncrypt && c->Session->UseFastRC4 == false)\r
3730         {\r
3731                 c->Session->UseSSLDataEncryption = true;\r
3732         }\r
3733         else\r
3734         {\r
3735                 c->Session->UseSSLDataEncryption = false;\r
3736         }\r
3737 \r
3738         PrintStatus(sess, L"free");\r
3739 \r
3740         CLog(c->Cedar->Client, "LC_CONNECT_2", c->Session->ClientOption->AccountName,\r
3741                 session_name);\r
3742 \r
3743         if (c->Session->LinkModeClient && c->Session->Link != NULL)\r
3744         {\r
3745                 HLog(c->Session->Link->Hub, "LH_CONNECT_2", c->Session->ClientOption->AccountName, session_name);\r
3746         }\r
3747 \r
3748         // セッションのメインルーチン\r
3749         SessionMain(c->Session);\r
3750 \r
3751         ok = true;\r
3752 \r
3753         if (c->Err == ERR_USER_CANCEL)\r
3754         {\r
3755                 ret = true;\r
3756         }\r
3757 \r
3758 CLEANUP:\r
3759         c->FirstSock = NULL;\r
3760 \r
3761         if (p != NULL)\r
3762         {\r
3763                 FreePack(p);\r
3764         }\r
3765 \r
3766         Disconnect(s);\r
3767         ReleaseSock(s);\r
3768 \r
3769         Debug("Error: %u\n", c->Err);\r
3770 \r
3771         if (ok == false)\r
3772         {\r
3773                 PrintStatus(sess, L"free");\r
3774         }\r
3775 \r
3776         return ret;\r
3777 }\r
3778 \r
3779 // Welcome パケットのパース\r
3780 bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,\r
3781                                                   char *connection_name, UINT connection_name_size,\r
3782                                                   POLICY **policy)\r
3783 {\r
3784         // 引数チェック\r
3785         if (p == NULL || session_name == NULL || connection_name == NULL || policy == NULL)\r
3786         {\r
3787                 return false;\r
3788         }\r
3789 \r
3790         // セッション名\r
3791         if (PackGetStr(p, "session_name", session_name, session_name_size) == false)\r
3792         {\r
3793                 return false;\r
3794         }\r
3795 \r
3796         // コネクション名\r
3797         if (PackGetStr(p, "connection_name", connection_name, connection_name_size) == false)\r
3798         {\r
3799                 return false;\r
3800         }\r
3801 \r
3802         // ポリシー\r
3803         *policy = PackGetPolicy(p);\r
3804         if (*policy == NULL)\r
3805         {\r
3806                 return false;\r
3807         }\r
3808 \r
3809         return true;\r
3810 }\r
3811 \r
3812 // Welcome パケットの生成\r
3813 PACK *PackWelcome(SESSION *s)\r
3814 {\r
3815         PACK *p;\r
3816         // 引数チェック\r
3817         if (s == NULL)\r
3818         {\r
3819                 return NULL;\r
3820         }\r
3821 \r
3822         p = NewPack();\r
3823 \r
3824         // セッション名\r
3825         PackAddStr(p, "session_name", s->Name);\r
3826 \r
3827         // コネクション名\r
3828         PackAddStr(p, "connection_name", s->Connection->Name);\r
3829 \r
3830         // パラメータ\r
3831         PackAddInt(p, "max_connection", s->MaxConnection);\r
3832         PackAddInt(p, "use_encrypt", s->UseEncrypt == false ? 0 : 1);\r
3833         PackAddInt(p, "use_fast_rc4", s->UseFastRC4 == false ? 0 : 1);\r
3834         PackAddInt(p, "use_compress", s->UseCompress == false ? 0 : 1);\r
3835         PackAddInt(p, "half_connection", s->HalfConnection == false ? 0 : 1);\r
3836         PackAddInt(p, "timeout", s->Timeout);\r
3837         PackAddInt(p, "qos", s->QoS ? 1 : 0);\r
3838 \r
3839         // セッションキー\r
3840         PackAddData(p, "session_key", s->SessionKey, SHA1_SIZE);\r
3841         PackAddInt(p, "session_key_32", s->SessionKey32);\r
3842 \r
3843         // ポリシー\r
3844         PackAddPolicy(p, s->Policy);\r
3845 \r
3846         // VLAN ID\r
3847         PackAddInt(p, "vlan_id", s->VLanId);\r
3848 \r
3849         if (s->Connection->Protocol == CONNECTION_UDP)\r
3850         {\r
3851                 // UDP プロトコルの場合、2 組のキーを生成する\r
3852                 Rand(s->UdpSendKey, sizeof(s->UdpSendKey));\r
3853                 Rand(s->UdpRecvKey, sizeof(s->UdpRecvKey));\r
3854 \r
3855                 // クライアントには鍵を反転して送る\r
3856                 PackAddData(p, "udp_send_key", s->UdpRecvKey, sizeof(s->UdpRecvKey));\r
3857                 PackAddData(p, "udp_recv_key", s->UdpSendKey, sizeof(s->UdpSendKey));\r
3858         }\r
3859 \r
3860         // no_send_signature\r
3861         if (s->NoSendSignature)\r
3862         {\r
3863                 PackAddBool(p, "no_send_signature", true);\r
3864         }\r
3865 \r
3866         return p;\r
3867 }\r
3868 \r
3869 #define PACK_ADD_POLICY_BOOL(name, value)       \\r
3870         PackAddInt(p, "policy:" name, y->value == false ? 0 : 1)\r
3871 #define PACK_ADD_POLICY_UINT(name, value)       \\r
3872         PackAddInt(p, "policy:" name, y->value)\r
3873 #define PACK_GET_POLICY_BOOL(name, value)       \\r
3874         y->value = (PackGetInt(p, "policy:" name) == 0 ? false : true)\r
3875 #define PACK_GET_POLICY_UINT(name, value)       \\r
3876         y->value = PackGetInt(p, "policy:" name)\r
3877 \r
3878 // セッションキーを PACK から取得\r
3879 bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32)\r
3880 {\r
3881         // 引数チェック\r
3882         if (p == NULL || session_key == NULL || session_key_32 == NULL)\r
3883         {\r
3884                 return false;\r
3885         }\r
3886 \r
3887         if (PackGetDataSize(p, "session_key") != SHA1_SIZE)\r
3888         {\r
3889                 return false;\r
3890         }\r
3891         if (PackGetData(p, "session_key", session_key) == false)\r
3892         {\r
3893                 return false;\r
3894         }\r
3895         *session_key_32 = PackGetInt(p, "session_key_32");\r
3896 \r
3897         return true;\r
3898 }\r
3899 \r
3900 // ポリシーを PACK から取得\r
3901 POLICY *PackGetPolicy(PACK *p)\r
3902 {\r
3903         // このあたりは急いで実装したのでコードがあまり美しくない。\r
3904         POLICY *y;\r
3905         // 引数チェック\r
3906         if (p == NULL)\r
3907         {\r
3908                 return NULL;\r
3909         }\r
3910 \r
3911         y = ZeroMalloc(sizeof(POLICY));\r
3912 \r
3913         // bool 値\r
3914         // Ver 2\r
3915         PACK_GET_POLICY_BOOL("Access", Access);\r
3916         PACK_GET_POLICY_BOOL("DHCPFilter", DHCPFilter);\r
3917         PACK_GET_POLICY_BOOL("DHCPNoServer", DHCPNoServer);\r
3918         PACK_GET_POLICY_BOOL("DHCPForce", DHCPForce);\r
3919         PACK_GET_POLICY_BOOL("NoBridge", NoBridge);\r
3920         PACK_GET_POLICY_BOOL("NoRouting", NoRouting);\r
3921         PACK_GET_POLICY_BOOL("PrivacyFilter", PrivacyFilter);\r
3922         PACK_GET_POLICY_BOOL("NoServer", NoServer);\r
3923         PACK_GET_POLICY_BOOL("CheckMac", CheckMac);\r
3924         PACK_GET_POLICY_BOOL("CheckIP", CheckIP);\r
3925         PACK_GET_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);\r
3926         PACK_GET_POLICY_BOOL("MonitorPort", MonitorPort);\r
3927         PACK_GET_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);\r
3928         PACK_GET_POLICY_BOOL("FixPassword", FixPassword);\r
3929         PACK_GET_POLICY_BOOL("NoQoS", NoQoS);\r
3930         // Ver 3\r
3931         PACK_GET_POLICY_BOOL("RSandRAFilter", RSandRAFilter);\r
3932         PACK_GET_POLICY_BOOL("RAFilter", RAFilter);\r
3933         PACK_GET_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);\r
3934         PACK_GET_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);\r
3935         PACK_GET_POLICY_BOOL("NoRoutingV6", NoRoutingV6);\r
3936         PACK_GET_POLICY_BOOL("CheckIPv6", CheckIPv6);\r
3937         PACK_GET_POLICY_BOOL("NoServerV6", NoServerV6);\r
3938         PACK_GET_POLICY_BOOL("NoSavePassword", NoSavePassword);\r
3939         PACK_GET_POLICY_BOOL("FilterIPv4", FilterIPv4);\r
3940         PACK_GET_POLICY_BOOL("FilterIPv6", FilterIPv6);\r
3941         PACK_GET_POLICY_BOOL("FilterNonIP", FilterNonIP);\r
3942         PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);\r
3943         PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);\r
3944 \r
3945         // UINT 値\r
3946         // Ver 2\r
3947         PACK_GET_POLICY_UINT("MaxConnection", MaxConnection);\r
3948         PACK_GET_POLICY_UINT("TimeOut", TimeOut);\r
3949         PACK_GET_POLICY_UINT("MaxMac", MaxMac);\r
3950         PACK_GET_POLICY_UINT("MaxIP", MaxIP);\r
3951         PACK_GET_POLICY_UINT("MaxUpload", MaxUpload);\r
3952         PACK_GET_POLICY_UINT("MaxDownload", MaxDownload);\r
3953         PACK_GET_POLICY_UINT("MultiLogins", MultiLogins);\r
3954         // Ver 3\r
3955         PACK_GET_POLICY_UINT("MaxIPv6", MaxIPv6);\r
3956         PACK_GET_POLICY_UINT("AutoDisconnect", AutoDisconnect);\r
3957         PACK_GET_POLICY_UINT("VLanId", VLanId);\r
3958 \r
3959         // Ver 3 フラグ\r
3960         PACK_GET_POLICY_BOOL("Ver3", Ver3);\r
3961 \r
3962         return y;\r
3963 }\r
3964 \r
3965 // ポリシーを PACK に挿入\r
3966 void PackAddPolicy(PACK *p, POLICY *y)\r
3967 {\r
3968         // このあたりは急いで実装したのでコードがあまり美しくない。\r
3969         // 引数チェック\r
3970         if (p == NULL || y == NULL)\r
3971         {\r
3972                 return;\r
3973         }\r
3974 \r
3975         // bool 値\r
3976         // Ver 2\r
3977         PACK_ADD_POLICY_BOOL("Access", Access);\r
3978         PACK_ADD_POLICY_BOOL("DHCPFilter", DHCPFilter);\r
3979         PACK_ADD_POLICY_BOOL("DHCPNoServer", DHCPNoServer);\r
3980         PACK_ADD_POLICY_BOOL("DHCPForce", DHCPForce);\r
3981         PACK_ADD_POLICY_BOOL("NoBridge", NoBridge);\r
3982         PACK_ADD_POLICY_BOOL("NoRouting", NoRouting);\r
3983         PACK_ADD_POLICY_BOOL("PrivacyFilter", PrivacyFilter);\r
3984         PACK_ADD_POLICY_BOOL("NoServer", NoServer);\r
3985         PACK_ADD_POLICY_BOOL("CheckMac", CheckMac);\r
3986         PACK_ADD_POLICY_BOOL("CheckIP", CheckIP);\r
3987         PACK_ADD_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);\r
3988         PACK_ADD_POLICY_BOOL("MonitorPort", MonitorPort);\r
3989         PACK_ADD_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);\r
3990         PACK_ADD_POLICY_BOOL("FixPassword", FixPassword);\r
3991         PACK_ADD_POLICY_BOOL("NoQoS", NoQoS);\r
3992         // Ver 3\r
3993         PACK_ADD_POLICY_BOOL("RSandRAFilter", RSandRAFilter);\r
3994         PACK_ADD_POLICY_BOOL("RAFilter", RAFilter);\r
3995         PACK_ADD_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);\r
3996         PACK_ADD_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);\r
3997         PACK_ADD_POLICY_BOOL("NoRoutingV6", NoRoutingV6);\r
3998         PACK_ADD_POLICY_BOOL("CheckIPv6", CheckIPv6);\r
3999         PACK_ADD_POLICY_BOOL("NoServerV6", NoServerV6);\r
4000         PACK_ADD_POLICY_BOOL("NoSavePassword", NoSavePassword);\r
4001         PACK_ADD_POLICY_BOOL("FilterIPv4", FilterIPv4);\r
4002         PACK_ADD_POLICY_BOOL("FilterIPv6", FilterIPv6);\r
4003         PACK_ADD_POLICY_BOOL("FilterNonIP", FilterNonIP);\r
4004         PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);\r
4005         PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);\r
4006 \r
4007         // UINT 値\r
4008         // Ver 2\r
4009         PACK_ADD_POLICY_UINT("MaxConnection", MaxConnection);\r
4010         PACK_ADD_POLICY_UINT("TimeOut", TimeOut);\r
4011         PACK_ADD_POLICY_UINT("MaxMac", MaxMac);\r
4012         PACK_ADD_POLICY_UINT("MaxIP", MaxIP);\r
4013         PACK_ADD_POLICY_UINT("MaxUpload", MaxUpload);\r
4014         PACK_ADD_POLICY_UINT("MaxDownload", MaxDownload);\r
4015         PACK_ADD_POLICY_UINT("MultiLogins", MultiLogins);\r
4016         // Ver 3\r
4017         PACK_ADD_POLICY_UINT("MaxIPv6", MaxIPv6);\r
4018         PACK_ADD_POLICY_UINT("AutoDisconnect", AutoDisconnect);\r
4019         PACK_ADD_POLICY_UINT("VLanId", VLanId);\r
4020 \r
4021         // Ver 3 フラグ\r
4022         PackAddBool(p, "policy:Ver3", true);\r
4023 }\r
4024 \r
4025 // 追加接続用の認証データをアップロードする\r
4026 bool ClientUploadAuth2(CONNECTION *c, SOCK *s)\r
4027 {\r
4028         PACK *p = NULL;\r
4029         // 引数チェック\r
4030         if (c == NULL)\r
4031         {\r
4032                 return false;\r
4033         }\r
4034 \r
4035         p = PackAdditionalConnect(c->Session->SessionKey);\r
4036 \r
4037         PackAddClientVersion(p, c);\r
4038 \r
4039         if (HttpClientSend(s, p) == false)\r
4040         {\r
4041                 FreePack(p);\r
4042                 return false;\r
4043         }\r
4044         FreePack(p);\r
4045 \r
4046         return true;\r
4047 }\r
4048 \r
4049 // NOOP を送信する\r
4050 void ClientUploadNoop(CONNECTION *c)\r
4051 {\r
4052         PACK *p;\r
4053         // 引数チェック\r
4054         if (c == NULL)\r
4055         {\r
4056                 return;\r
4057         }\r
4058 \r
4059         p = PackError(0);\r
4060         PackAddInt(p, "noop", 1);\r
4061         HttpClientSend(c->FirstSock, p);\r
4062         FreePack(p);\r
4063 \r
4064         p = HttpClientRecv(c->FirstSock);\r
4065         if (p != NULL)\r
4066         {\r
4067                 FreePack(p);\r
4068         }\r
4069 }\r
4070 \r
4071 // クライアントのバージョン情報を PACK に追加する\r
4072 void PackAddClientVersion(PACK *p, CONNECTION *c)\r
4073 {\r
4074         // 引数チェック\r
4075         if (p == NULL || c == NULL)\r
4076         {\r
4077                 return;\r
4078         }\r
4079 \r
4080         PackAddStr(p, "client_str", c->ClientStr);\r
4081         PackAddInt(p, "client_ver", c->ClientVer);\r
4082         PackAddInt(p, "client_build", c->ClientBuild);\r
4083 }\r
4084 \r
4085 // 新規接続用の認証データをアップロードする\r
4086 bool ClientUploadAuth(CONNECTION *c)\r
4087 {\r
4088         PACK *p = NULL;\r
4089         CLIENT_AUTH *a;\r
4090         CLIENT_OPTION *o;\r
4091         X *x;\r
4092         bool ret;\r
4093         NODE_INFO info;\r
4094         UCHAR secure_password[SHA1_SIZE];\r
4095         UCHAR sign[4096 / 8];\r
4096         UCHAR unique[SHA1_SIZE];\r
4097         RPC_WINVER v;\r
4098         // 引数チェック\r
4099         if (c == NULL)\r
4100         {\r
4101                 return false;\r
4102         }\r
4103 \r
4104         Zero(sign, sizeof(sign));\r
4105 \r
4106         a = c->Session->ClientAuth;\r
4107         o = c->Session->ClientOption;\r
4108 \r
4109         if (c->UseTicket == false)\r
4110         {\r
4111                 switch (a->AuthType)\r
4112                 {\r
4113                 case CLIENT_AUTHTYPE_ANONYMOUS:\r
4114                         // 匿名認証\r
4115                         p = PackLoginWithAnonymous(o->HubName, a->Username);\r
4116                         break;\r
4117 \r
4118                 case CLIENT_AUTHTYPE_PASSWORD:\r
4119                         // パスワード認証\r
4120                         SecurePassword(secure_password, a->HashedPassword, c->Random);\r
4121                         p = PackLoginWithPassword(o->HubName, a->Username, secure_password);\r
4122                         break;\r
4123 \r
4124                 case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
4125                         // 平文パスワード認証\r
4126                         p = PackLoginWithPlainPassword(o->HubName, a->Username, a->PlainPassword);\r
4127                         break;\r
4128 \r
4129                 case CLIENT_AUTHTYPE_CERT:\r
4130                         // 証明書認証\r
4131                         if (a->ClientX != NULL && a->ClientX->is_compatible_bit &&\r
4132                                 a->ClientX->bits != 0 && (a->ClientX->bits / 8) <= sizeof(sign))\r
4133                         {\r
4134                                 if (RsaSignEx(sign, c->Random, SHA1_SIZE, a->ClientK, a->ClientX->bits))\r
4135                                 {\r
4136                                         p = PackLoginWithCert(o->HubName, a->Username, a->ClientX, sign, a->ClientX->bits / 8);\r
4137                                         c->ClientX = CloneX(a->ClientX);\r
4138                                 }\r
4139                         }\r
4140                         break;\r
4141 \r
4142                 case CLIENT_AUTHTYPE_SECURE:\r
4143                         // セキュアデバイスによる認証\r
4144                         if (ClientSecureSign(c, sign, c->Random, &x))\r
4145                         {\r
4146                                 p = PackLoginWithCert(o->HubName, a->Username, x, sign, 128);\r
4147                                 c->ClientX = CloneX(x);\r
4148                                 FreeX(x);\r
4149                         }\r
4150                         else\r
4151                         {\r
4152                                 c->Err = ERR_SECURE_DEVICE_OPEN_FAILED;\r
4153                                 c->Session->ForceStopFlag = true;\r
4154                         }\r
4155                         break;\r
4156                 }\r
4157         }\r
4158         else\r
4159         {\r
4160                 // チケット\r
4161                 p = NewPack();\r
4162                 PackAddStr(p, "method", "login");\r
4163                 PackAddStr(p, "hubname", o->HubName);\r
4164                 PackAddStr(p, "username", a->Username);\r
4165                 PackAddInt(p, "authtype", AUTHTYPE_TICKET);\r
4166                 PackAddData(p, "ticket", c->Ticket, SHA1_SIZE);\r
4167         }\r
4168 \r
4169         // 現在時刻\r
4170         PackAddInt64(p, "timestamp", SystemTime64());\r
4171 \r
4172         if (p == NULL)\r
4173         {\r
4174                 // エラー\r
4175                 if (c->Err != ERR_SECURE_DEVICE_OPEN_FAILED)\r
4176                 {\r
4177                         c->Err = ERR_PROTOCOL_ERROR;\r
4178                 }\r
4179                 return false;\r
4180         }\r
4181 \r
4182         PackAddClientVersion(p, c);\r
4183 \r
4184         // プロトコル\r
4185         PackAddInt(p, "protocol", c->Protocol);\r
4186 \r
4187         // バージョン等\r
4188         PackAddStr(p, "hello", c->ClientStr);\r
4189         PackAddInt(p, "version", c->ClientVer);\r
4190         PackAddInt(p, "build", c->ClientBuild);\r
4191         PackAddInt(p, "client_id", c->Cedar->ClientId);\r
4192 \r
4193         // 最大コネクション数\r
4194         PackAddInt(p, "max_connection", o->MaxConnection);\r
4195         // 暗号化使用フラグ\r
4196         PackAddInt(p, "use_encrypt", o->UseEncrypt == false ? 0 : 1);\r
4197         // 高速暗号化使用フラグ\r
4198         //      PackAddInt(p, "use_fast_rc4", o->UseFastRC4 == false ? 0 : 1);\r
4199         // データ圧縮使用フラグ\r
4200         PackAddInt(p, "use_compress", o->UseCompress == false ? 0 : 1);\r
4201         // ハーフコネクションフラグ\r
4202         PackAddInt(p, "half_connection", o->HalfConnection == false ? 0 : 1);\r
4203 \r
4204         // ブリッジ / ルーティングモードフラグ\r
4205         PackAddBool(p, "require_bridge_routing_mode", o->RequireBridgeRoutingMode);\r
4206 \r
4207         // モニタモードフラグ\r
4208         PackAddBool(p, "require_monitor_mode", o->RequireMonitorMode);\r
4209 \r
4210         // VoIP / QoS フラグ\r
4211         PackAddBool(p, "qos", o->DisableQoS ? false : true);\r
4212 \r
4213         // ユニーク ID\r
4214         GenerateMachineUniqueHash(unique);\r
4215         PackAddData(p, "unique_id", unique, SHA1_SIZE);\r
4216 \r
4217         // ノード情報\r
4218         CreateNodeInfo(&info, c);\r
4219         OutRpcNodeInfo(p, &info);\r
4220 \r
4221         // OS 情報\r
4222         GetWinVer(&v);\r
4223         OutRpcWinVer(p, &v);\r
4224 \r
4225         ret = HttpClientSend(c->FirstSock, p);\r
4226         if (ret == false)\r
4227         {\r
4228                 c->Err = ERR_DISCONNECTED;\r
4229         }\r
4230 \r
4231         FreePack(p);\r
4232 \r
4233         return ret;\r
4234 }\r
4235 \r
4236 // Hello パケットをアップロードする\r
4237 bool ServerUploadHello(CONNECTION *c)\r
4238 {\r
4239         PACK *p;\r
4240         // 引数チェック\r
4241         if (c == NULL)\r
4242         {\r
4243                 return false;\r
4244         }\r
4245 \r
4246         // 乱数生成\r
4247         Rand(c->Random, SHA1_SIZE);\r
4248 \r
4249         p = PackHello(c->Random, c->ServerVer, c->ServerBuild, c->ServerStr);\r
4250         if (HttpServerSend(c->FirstSock, p) == false)\r
4251         {\r
4252                 FreePack(p);\r
4253                 c->Err = ERR_DISCONNECTED;\r
4254                 return false;\r
4255         }\r
4256 \r
4257         FreePack(p);\r
4258 \r
4259         return true;\r
4260 }\r
4261 \r
4262 // Hello パケットをダウンロードする\r
4263 bool ClientDownloadHello(CONNECTION *c, SOCK *s)\r
4264 {\r
4265         PACK *p;\r
4266         UINT err;\r
4267         UCHAR random[SHA1_SIZE];\r
4268         // 引数チェック\r
4269         if (c == NULL)\r
4270         {\r
4271                 return false;\r
4272         }\r
4273 \r
4274         // データ受信\r
4275         p = HttpClientRecv(s);\r
4276         if (p == NULL)\r
4277         {\r
4278                 c->Err = ERR_SERVER_IS_NOT_VPN;\r
4279                 return false;\r
4280         }\r
4281 \r
4282         if (err = GetErrorFromPack(p))\r
4283         {\r
4284                 // エラー発生\r
4285                 c->Err = err;\r
4286                 FreePack(p);\r
4287                 return false;\r
4288         }\r
4289 \r
4290         // パケット解釈\r
4291         if (GetHello(p, random, &c->ServerVer, &c->ServerBuild, c->ServerStr, sizeof(c->ServerStr)) == false)\r
4292         {\r
4293                 c->Err = ERR_SERVER_IS_NOT_VPN;\r
4294                 FreePack(p);\r
4295                 return false;\r
4296         }\r
4297 \r
4298         if (c->FirstSock == s)\r
4299         {\r
4300                 Copy(c->Random, random, SHA1_SIZE);\r
4301         }\r
4302 \r
4303         FreePack(p);\r
4304 \r
4305         return true;\r
4306 }\r
4307 \r
4308 // シグネチャをダウンロードする\r
4309 bool ServerDownloadSignature(CONNECTION *c)\r
4310 {\r
4311         HTTP_HEADER *h;\r
4312         UCHAR *data;\r
4313         UINT data_size;\r
4314         SOCK *s;\r
4315         UINT num = 0, max = 19;\r
4316         // 引数チェック\r
4317         if (c == NULL)\r
4318         {\r
4319                 return false;\r
4320         }\r
4321 \r
4322         s = c->FirstSock;\r
4323 \r
4324         while (true)\r
4325         {\r
4326                 num++;\r
4327                 if (num > max)\r
4328                 {\r
4329                         // 切断\r
4330                         Disconnect(s);\r
4331                         c->Err = ERR_CLIENT_IS_NOT_VPN;\r
4332                         return false;\r
4333                 }\r
4334                 // ヘッダを受信する\r
4335                 h = RecvHttpHeader(s);\r
4336                 if (h == NULL)\r
4337                 {\r
4338                         c->Err = ERR_CLIENT_IS_NOT_VPN;\r
4339                         return false;\r
4340                 }\r
4341 \r
4342                 // 解釈する\r
4343                 if (StrCmpi(h->Method, "POST") == 0)\r
4344                 {\r
4345                         // POST なのでデータを受信する\r
4346                         data_size = GetContentLength(h);\r
4347                         if ((data_size > 3411 || data_size < 1411) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA)))\r
4348                         {\r
4349                                 // データが大きすぎる\r
4350                                 HttpSendForbidden(s, h->Target, NULL);\r
4351                                 FreeHttpHeader(h);\r
4352                                 c->Err = ERR_CLIENT_IS_NOT_VPN;\r
4353                                 return false;\r
4354                         }\r
4355                         data = Malloc(data_size);\r
4356                         if (RecvAll(s, data, data_size, s->SecureMode) == false)\r
4357                         {\r
4358                                 // データ受信失敗\r
4359                                 Free(data);\r
4360                                 FreeHttpHeader(h);\r
4361                                 c->Err = ERR_DISCONNECTED;\r
4362                                 return false;\r
4363                         }\r
4364                         // Target を確認する\r
4365                         if (StrCmpi(h->Target, HTTP_VPN_TARGET2) != 0)\r
4366                         {\r
4367                                 // ターゲットが不正\r
4368                                 HttpSendNotFound(s, h->Target);\r
4369                                 Free(data);\r
4370                                 FreeHttpHeader(h);\r
4371                         }\r
4372                         else\r
4373                         {\r
4374                                 if (((data_size == StrLen(HTTP_VPN_TARGET_POSTDATA)) && (Cmp(data, HTTP_VPN_TARGET_POSTDATA, data_size) == 0)) || (data_size >= 1411))\r
4375                                 {\r
4376                                         // VPN Client が接続してきた\r
4377                                         Free(data);\r
4378                                         FreeHttpHeader(h);\r
4379                                         return true;\r
4380                                 }\r
4381                                 else\r
4382                                 {\r
4383                                         // VPN Client 以外のソフトウェアが接続してきた\r
4384                                         HttpSendForbidden(s, h->Target, NULL);\r
4385                                         FreeHttpHeader(h);\r
4386                                 }\r
4387                         }\r
4388                 }\r
4389                 else\r
4390                 {\r
4391                         // これ以上解釈しても VPN クライアントで無い可能性が高いが\r
4392                         // 一応する\r
4393                         if (StrCmpi(h->Method, "GET") != 0)\r
4394                         {\r
4395                                 // サポートされていないメソッド呼び出し\r
4396                                 HttpSendNotImplemented(s, h->Method, h->Target, h->Version);\r
4397                         }\r
4398                         else\r
4399                         {\r
4400                                 if (StrCmpi(h->Target, "/") == 0)\r
4401                                 {\r
4402                                         // ルートディレクトリ\r
4403                                         HttpSendForbidden(c->FirstSock, h->Target, "");\r
4404                                 }\r
4405                                 else\r
4406                                 {\r
4407                                         // Not Found\r
4408                                         HttpSendNotFound(s, h->Target);\r
4409                                 }\r
4410                         }\r
4411                         FreeHttpHeader(h);\r
4412                 }\r
4413         }\r
4414 }\r
4415 \r
4416 // シグネチャをアップロードする\r
4417 bool ClientUploadSignature(SOCK *s)\r
4418 {\r
4419         HTTP_HEADER *h;\r
4420         // 引数チェック\r
4421         if (s == NULL)\r
4422         {\r
4423                 return false;\r
4424         }\r
4425 \r
4426         h = NewHttpHeader("POST", HTTP_VPN_TARGET2, "HTTP/1.1");\r
4427         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));\r
4428         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
4429 \r
4430         if (PostHttp(s, h, HTTP_VPN_TARGET_POSTDATA, StrLen(HTTP_VPN_TARGET_POSTDATA)) == false)\r
4431         {\r
4432                 FreeHttpHeader(h);\r
4433                 return false;\r
4434         }\r
4435 \r
4436         FreeHttpHeader(h);\r
4437 \r
4438         return true;\r
4439 }\r
4440 \r
4441 // サーバーへの接続を確立する\r
4442 SOCK *ClientConnectToServer(CONNECTION *c)\r
4443 {\r
4444         SOCK *s = NULL;\r
4445         X *x = NULL;\r
4446         K *k = NULL;\r
4447         // 引数チェック\r
4448         if (c == NULL)\r
4449         {\r
4450                 return NULL;\r
4451         }\r
4452 \r
4453         if (c->Halt)\r
4454         {\r
4455                 c->Err = ERR_USER_CANCEL;\r
4456                 return NULL;\r
4457         }\r
4458 \r
4459         // 接続してソケットを取得\r
4460         s = ClientConnectGetSocket(c, false);\r
4461         if (s == NULL)\r
4462         {\r
4463                 // 接続失敗\r
4464                 return NULL;\r
4465         }\r
4466 \r
4467         c->FirstSock = s;\r
4468 \r
4469         if (c->Halt)\r
4470         {\r
4471                 c->Err = ERR_USER_CANCEL;\r
4472                 ReleaseSock(s);\r
4473                 c->FirstSock = NULL;\r
4474                 return NULL;\r
4475         }\r
4476 \r
4477         // タイムアウト\r
4478         SetTimeout(s, CONNECTING_TIMEOUT);\r
4479 \r
4480         // SSL 通信の開始\r
4481         if (StartSSLEx(s, x, k, (c->DontUseTls1 ? false : true)) == false)\r
4482         {\r
4483                 // SSL 通信開始失敗\r
4484                 Disconnect(s);\r
4485                 ReleaseSock(s);\r
4486                 c->FirstSock = NULL;\r
4487                 c->Err = ERR_SERVER_IS_NOT_VPN;\r
4488                 return NULL;\r
4489         }\r
4490 \r
4491         if (s->RemoteX == NULL)\r
4492         {\r
4493                 // SSL 通信開始失敗\r
4494                 Disconnect(s);\r
4495                 ReleaseSock(s);\r
4496                 c->FirstSock = NULL;\r
4497                 c->Err = ERR_SERVER_IS_NOT_VPN;\r
4498                 return NULL;\r
4499         }\r
4500 \r
4501         return s;\r
4502 }\r
4503 \r
4504 // サーバーに接続しソケットを返す\r
4505 SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)\r
4506 {\r
4507         SOCK *s = NULL;\r
4508         CLIENT_OPTION *o;\r
4509         char *host_for_direct_connection;\r
4510         UINT port_for_direct_connection;\r
4511         wchar_t tmp[MAX_SIZE];\r
4512         SESSION *sess;\r
4513         volatile bool *cancel_flag = NULL;\r
4514         void *hWnd;\r
4515         // 引数チェック\r
4516         if (c == NULL)\r
4517         {\r
4518                 return NULL;\r
4519         }\r
4520 \r
4521         sess = c->Session;\r
4522 \r
4523         if (sess != NULL)\r
4524         {\r
4525                 cancel_flag = &sess->CancelConnect;\r
4526         }\r
4527 \r
4528         hWnd = c->hWndForUI;\r
4529 \r
4530         o = c->Session->ClientOption;\r
4531 \r
4532         if (c->RestoreServerNameAndPort && additional_connect)\r
4533         {\r
4534                 // サーバー名とポート番号を元に戻す\r
4535                 c->RestoreServerNameAndPort = false;\r
4536 \r
4537                 StrCpy(c->ServerName, sizeof(c->ServerName), o->Hostname);\r
4538                 c->ServerPort = o->Port;\r
4539         }\r
4540 \r
4541         host_for_direct_connection = c->ServerName;\r
4542         port_for_direct_connection = c->ServerPort;\r
4543 \r
4544         if (o->PortUDP != 0)\r
4545         {\r
4546                 // UDP Connection\r
4547                 goto UDP_CONNECTION;\r
4548         }\r
4549 \r
4550         switch (o->ProxyType)\r
4551         {\r
4552         case PROXY_DIRECT:      // TCP/IP\r
4553 UDP_CONNECTION:\r
4554                 UniFormat(tmp, sizeof(tmp), _UU("STATUS_4"), c->ServerName);\r
4555                 PrintStatus(sess, tmp);\r
4556                 // 本番\r
4557                 s = TcpIpConnectEx(host_for_direct_connection, port_for_direct_connection,\r
4558                         (bool *)cancel_flag, hWnd);\r
4559                 if (s == NULL)\r
4560                 {\r
4561                         // 接続失敗\r
4562                         c->Err = ERR_CONNECT_FAILED;\r
4563                         return NULL;\r
4564                 }\r
4565                 break;\r
4566 \r
4567         case PROXY_HTTP:        // HTTP Proxy\r
4568                 host_for_direct_connection = o->ProxyName;\r
4569                 port_for_direct_connection = o->ProxyPort;\r
4570 \r
4571                 UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);\r
4572                 PrintStatus(sess, tmp);\r
4573                 // プロキシ接続\r
4574                 s = ProxyConnectEx(c, host_for_direct_connection, port_for_direct_connection,\r
4575                         c->ServerName, c->ServerPort, o->ProxyUsername, o->ProxyPassword,\r
4576                         additional_connect, (bool *)cancel_flag, hWnd);\r
4577                 if (s == NULL)\r
4578                 {\r
4579                         // 接続失敗\r
4580                         return NULL;\r
4581                 }\r
4582                 break;\r
4583 \r
4584         case PROXY_SOCKS:       // SOCKS Proxy\r
4585                 host_for_direct_connection = o->ProxyName;\r
4586 \r
4587                 port_for_direct_connection = o->ProxyPort;\r
4588 \r
4589                 UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);\r
4590                 PrintStatus(sess, tmp);\r
4591                 // SOCKS 接続\r
4592                 s = SocksConnectEx(c, host_for_direct_connection, port_for_direct_connection,\r
4593                         c->ServerName, c->ServerPort, o->ProxyUsername,\r
4594                         additional_connect, (bool *)cancel_flag, hWnd);\r
4595                 if (s == NULL)\r
4596                 {\r
4597                         // 接続失敗\r
4598                         return NULL;\r
4599                 }\r
4600                 break;\r
4601         }\r
4602 \r
4603         if (s == NULL)\r
4604         {\r
4605                 // 接続失敗\r
4606                 c->Err = ERR_CONNECT_FAILED;\r
4607         }\r
4608         else\r
4609         {\r
4610                 // 接続成功\r
4611                 // IP アドレスを控えておく\r
4612                 if (GetIP(&c->Session->ServerIP, host_for_direct_connection) == false)\r
4613                 {\r
4614                         Copy(&c->Session->ServerIP, &s->RemoteIP, sizeof(IP));\r
4615                 }\r
4616         }\r
4617 \r
4618         return s;\r
4619 }\r
4620 \r
4621 // SOCKS 経由で接続する\r
4622 SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,\r
4623                                    char *server_host_name, UINT server_port,\r
4624                                    char *username, bool additional_connect)\r
4625 {\r
4626         return SocksConnectEx(c, proxy_host_name, proxy_port,\r
4627                 server_host_name, server_port, username, additional_connect, NULL, NULL);\r
4628 }\r
4629 SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,\r
4630                                    char *server_host_name, UINT server_port,\r
4631                                    char *username, bool additional_connect,\r
4632                                    bool *cancel_flag, void *hWnd)\r
4633 {\r
4634         SOCK *s = NULL;\r
4635         IP ip;\r
4636         // 引数チェック\r
4637         if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL\r
4638                 || server_port == 0)\r
4639         {\r
4640                 c->Err = ERR_PROXY_CONNECT_FAILED;\r
4641                 return NULL;\r
4642         }\r
4643 \r
4644         // 接続先サーバーの IP アドレスを取得す\r
4645         if (GetIP(&ip, server_host_name) == false)\r
4646         {\r
4647                 // 失敗\r
4648                 c->Err = ERR_CONNECT_FAILED;\r
4649                 return NULL;\r
4650         }\r
4651 \r
4652         if (c->Halt)\r
4653         {\r
4654                 // 停止\r
4655                 c->Err = ERR_USER_CANCEL;\r
4656                 return NULL;\r
4657         }\r
4658 \r
4659         // 接続\r
4660         s = TcpConnectEx2(proxy_host_name, proxy_port, 0, cancel_flag, hWnd);\r
4661         if (s == NULL)\r
4662         {\r
4663                 // 失敗\r
4664                 c->Err = ERR_PROXY_CONNECT_FAILED;\r
4665                 return NULL;\r
4666         }\r
4667 \r
4668         // タイムアウト設定\r
4669         SetTimeout(s, CONNECTING_TIMEOUT_PROXY);\r
4670 \r
4671         if (additional_connect == false)\r
4672         {\r
4673                 c->FirstSock = s;\r
4674         }\r
4675 \r
4676         // リクエストパケット送信\r
4677         if (SocksSendRequestPacket(c, s, server_port, &ip, username) == false)\r
4678         {\r
4679                 // 失敗\r
4680                 if (additional_connect == false)\r
4681                 {\r
4682                         c->FirstSock = NULL;\r
4683                 }\r
4684                 Disconnect(s);\r
4685                 ReleaseSock(s);\r
4686                 return NULL;\r
4687         }\r
4688 \r
4689         // 応答パケット受信\r
4690         if (SocksRecvResponsePacket(c, s) == false)\r
4691         {\r
4692                 // 失敗\r
4693                 if (additional_connect == false)\r
4694                 {\r
4695                         c->FirstSock = NULL;\r
4696                 }\r
4697                 Disconnect(s);\r
4698                 ReleaseSock(s);\r
4699                 return NULL;\r
4700         }\r
4701 \r
4702         SetTimeout(s, INFINITE);\r
4703 \r
4704         return s;\r
4705 }\r
4706 \r
4707 // SOCKS 応答パケットを受信する\r
4708 bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s)\r
4709 {\r
4710         BUF *b;\r
4711         UINT size = 8;\r
4712         UCHAR tmp[8];\r
4713         UCHAR vn, cd;\r
4714         // 引数チェック\r
4715         if (c == NULL || s == NULL)\r
4716         {\r
4717                 return false;\r
4718         }\r
4719 \r
4720         if (RecvAll(s, tmp, sizeof(tmp), false) == false)\r
4721         {\r
4722                 c->Err = ERR_DISCONNECTED;\r
4723                 return false;\r
4724         }\r
4725 \r
4726         b = NewBuf();\r
4727         WriteBuf(b, tmp, sizeof(tmp));\r
4728         SeekBuf(b, 0, 0);\r
4729 \r
4730         ReadBuf(b, &vn, 1);\r
4731         ReadBuf(b, &cd, 1);\r
4732 \r
4733         FreeBuf(b);\r
4734 \r
4735         if (vn != 0)\r
4736         {\r
4737                 c->Err = ERR_PROXY_ERROR;\r
4738                 return false;\r
4739         }\r
4740 \r
4741         switch (cd)\r
4742         {\r
4743         case 90:\r
4744                 // 成功\r
4745                 return true;\r
4746 \r
4747         case 93:\r
4748                 // 認証失敗\r
4749                 c->Err = ERR_PROXY_AUTH_FAILED;\r
4750                 return false;\r
4751 \r
4752         default:\r
4753                 // サーバーへの接続失敗\r
4754                 c->Err = ERR_CONNECT_FAILED;\r
4755                 return false;\r
4756         }\r
4757 }\r
4758 \r
4759 // SOCKS リクエストパケットを送信する\r
4760 bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid)\r
4761 {\r
4762         BUF *b;\r
4763         UCHAR vn, cd;\r
4764         USHORT port;\r
4765         UINT ip;\r
4766         bool ret;\r
4767         // 引数チェック\r
4768         if (s == NULL || dest_port == 0 || dest_ip == NULL || c == NULL)\r
4769         {\r
4770                 return false;\r
4771         }\r
4772         if (userid == NULL)\r
4773         {\r
4774                 userid = "";\r
4775         }\r
4776 \r
4777         b = NewBuf();\r
4778         vn = 4;\r
4779         cd = 1;\r
4780         WriteBuf(b, &vn, 1);\r
4781         WriteBuf(b, &cd, 1);\r
4782         port = Endian16((USHORT)dest_port);\r
4783         ip = IPToUINT(dest_ip);\r
4784         WriteBuf(b, &port, 2);\r
4785         WriteBuf(b, &ip, 4);\r
4786         WriteBuf(b, userid, StrLen(userid) + 1);\r
4787 \r
4788         ret = SendAll(s, b->Buf, b->Size, false);\r
4789         if (ret == false)\r
4790         {\r
4791                 c->Err = ERR_DISCONNECTED;\r
4792         }\r
4793 \r
4794         FreeBuf(b);\r
4795 \r
4796         return ret;\r
4797 }\r
4798 \r
4799 // プロキシ経由で接続する\r
4800 SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,\r
4801                                    char *server_host_name, UINT server_port,\r
4802                                    char *username, char *password, bool additional_connect)\r
4803 {\r
4804         return ProxyConnectEx(c, proxy_host_name, proxy_port,\r
4805                 server_host_name, server_port, username, password, additional_connect, NULL, NULL);\r
4806 }\r
4807 SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,\r
4808                                    char *server_host_name, UINT server_port,\r
4809                                    char *username, char *password, bool additional_connect,\r
4810                                    bool *cancel_flag, void *hWnd)\r
4811 {\r
4812         SOCK *s = NULL;\r
4813         bool use_auth = false;\r
4814         char tmp[MAX_SIZE];\r
4815         char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];\r
4816         char basic_str[MAX_SIZE * 2];\r
4817         UINT http_error_code;\r
4818         HTTP_HEADER *h;\r
4819         // 引数チェック\r
4820         if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL ||\r
4821                 server_port == 0)\r
4822         {\r
4823                 c->Err = ERR_PROXY_CONNECT_FAILED;\r
4824                 return NULL;\r
4825         }\r
4826         if (username != NULL && password != NULL &&\r
4827                 (StrLen(username) != 0 || StrLen(password) != 0))\r
4828         {\r
4829                 use_auth = true;\r
4830         }\r
4831 \r
4832         if (c->Halt)\r
4833         {\r
4834                 // 停止\r
4835                 c->Err = ERR_USER_CANCEL;\r
4836                 return NULL;\r
4837         }\r
4838 \r
4839         // 接続\r
4840         s = TcpConnectEx2(proxy_host_name, proxy_port, 0, cancel_flag, hWnd);\r
4841         if (s == NULL)\r
4842         {\r
4843                 // 失敗\r
4844                 c->Err = ERR_PROXY_CONNECT_FAILED;\r
4845                 return NULL;\r
4846         }\r
4847 \r
4848         // タイムアウト設定\r
4849         SetTimeout(s, CONNECTING_TIMEOUT_PROXY);\r
4850 \r
4851         if (additional_connect == false)\r
4852         {\r
4853                 c->FirstSock = s;\r
4854         }\r
4855 \r
4856         // HTTP ヘッダ生成\r
4857         if (IsStrIPv6Address(server_host_name))\r
4858         {\r
4859                 IP ip;\r
4860                 char iptmp[MAX_PATH];\r
4861 \r
4862                 StrToIP(&ip, server_host_name);\r
4863                 IPToStr(iptmp, sizeof(iptmp), &ip);\r
4864 \r
4865                 Format(tmp, sizeof(tmp), "[%s]:%u", iptmp, server_port);\r
4866         }\r
4867         else\r
4868         {\r
4869                 Format(tmp, sizeof(tmp), "%s:%u", server_host_name, server_port);\r
4870         }\r
4871 \r
4872         h = NewHttpHeader("CONNECT", tmp, "HTTP/1.0");\r
4873         AddHttpValue(h, NewHttpValue("User-Agent", c->Cedar->HttpUserAgent));\r
4874         Debug("proxy user agent = %s\n", c->Cedar->HttpUserAgent);\r
4875         AddHttpValue(h, NewHttpValue("Host", server_host_name));\r
4876         AddHttpValue(h, NewHttpValue("Content-Length", "0"));\r
4877         AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));\r
4878         AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));\r
4879 \r
4880         if (use_auth)\r
4881         {\r
4882                 wchar_t tmp[MAX_SIZE];\r
4883                 UniFormat(tmp, sizeof(tmp), _UU("STATUS_3"), server_host_name);\r
4884                 // 認証文字列の生成\r
4885                 Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",\r
4886                         username, password);\r
4887 \r
4888                 // Base64 エンコード\r
4889                 Zero(auth_b64_str, sizeof(auth_b64_str));\r
4890                 Encode64(auth_b64_str, auth_tmp_str);\r
4891                 Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);\r
4892 \r
4893                 AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));\r
4894         }\r
4895 \r
4896         // 送信\r
4897         if (SendHttpHeader(s, h) == false)\r
4898         {\r
4899                 // 失敗\r
4900                 if (additional_connect == false)\r
4901                 {\r
4902                         c->FirstSock = NULL;\r
4903                 }\r
4904                 FreeHttpHeader(h);\r
4905                 Disconnect(s);\r
4906                 ReleaseSock(s);\r
4907                 c->Err = ERR_PROXY_ERROR;\r
4908                 return NULL;\r
4909         }\r
4910 \r
4911         FreeHttpHeader(h);\r
4912 \r
4913         if (c->Halt)\r
4914         {\r
4915                 // 停止\r
4916                 if (additional_connect == false)\r
4917                 {\r
4918                         c->FirstSock = NULL;\r
4919                 }\r
4920                 Disconnect(s);\r
4921                 ReleaseSock(s);\r
4922                 c->Err = ERR_USER_CANCEL;\r
4923                 return NULL;\r
4924         }\r
4925 \r
4926         // 結果を受信\r
4927         h = RecvHttpHeader(s);\r
4928         if (h == NULL)\r
4929         {\r
4930                 // 失敗\r
4931                 if (additional_connect == false)\r
4932                 {\r
4933                         c->FirstSock = NULL;\r
4934                 }\r
4935                 FreeHttpHeader(h);\r
4936                 Disconnect(s);\r
4937                 ReleaseSock(s);\r
4938                 c->Err = ERR_PROXY_ERROR;\r
4939                 return NULL;\r
4940         }\r
4941 \r
4942         http_error_code = 0;\r
4943         if (StrLen(h->Method) == 8)\r
4944         {\r
4945                 if (Cmp(h->Method, "HTTP/1.", 7) == 0)\r
4946                 {\r
4947                         http_error_code = ToInt(h->Target);\r
4948                 }\r
4949         }\r
4950         FreeHttpHeader(h);\r
4951 \r
4952         // コードを確認\r
4953         switch (http_error_code)\r
4954         {\r
4955         case 401:\r
4956         case 403:\r
4957         case 407:\r
4958                 // 認証失敗\r
4959                 if (additional_connect == false)\r
4960                 {\r
4961                         c->FirstSock = NULL;\r
4962                 }\r
4963                 Disconnect(s);\r
4964                 ReleaseSock(s);\r
4965                 c->Err = ERR_PROXY_AUTH_FAILED;\r
4966                 return NULL;\r
4967 \r
4968         default:\r
4969                 if ((http_error_code / 100) == 2)\r
4970                 {\r
4971                         // 成功\r
4972                         SetTimeout(s, INFINITE);\r
4973                         return s;\r
4974                 }\r
4975                 else\r
4976                 {\r
4977                         // 不明な結果を受信\r
4978                         if (additional_connect == false)\r
4979                         {\r
4980                                 c->FirstSock = NULL;\r
4981                         }\r
4982                         Disconnect(s);\r
4983                         ReleaseSock(s);\r
4984                         c->Err = ERR_PROXY_ERROR;\r
4985                         return NULL;\r
4986                 }\r
4987         }\r
4988 }\r
4989 \r
4990 // TCP 接続関数\r
4991 SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd)\r
4992 {\r
4993 #ifdef  OS_WIN32\r
4994         if (hWnd == NULL)\r
4995         {\r
4996                 return ConnectEx2(hostname, port, timeout, cancel_flag);\r
4997         }\r
4998         else\r
4999         {\r
5000                 return WinConnectEx2((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL);\r
5001         }\r
5002 #else   // OS_WIN32\r
5003         return ConnectEx2(hostname, port, timeout, cancel_flag);\r
5004 #endif  // OS_WIN32\r
5005 }\r
5006 \r
5007 // TCP/IP で接続する\r
5008 SOCK *TcpIpConnect(char *hostname, UINT port)\r
5009 {\r
5010         return TcpIpConnectEx(hostname, port, NULL, NULL);\r
5011 }\r
5012 SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd)\r
5013 {\r
5014         SOCK *s = NULL;\r
5015         // 引数チェック\r
5016         if (hostname == NULL || port == 0)\r
5017         {\r
5018                 return NULL;\r
5019         }\r
5020 \r
5021         s = TcpConnectEx2(hostname, port, 0, cancel_flag, hWnd);\r
5022         if (s == NULL)\r
5023         {\r
5024                 return NULL;\r
5025         }\r
5026 \r
5027         return s;\r
5028 }\r
5029 \r
5030 // PACK にダミーのエントリを作成する\r
5031 // Q. なぜランダムなサイズのランダムデータをここで挿入するのか?\r
5032 // A. ネットワーク経路中の盗聴者によってこの SSL 通信が VPN 通信であること\r
5033 //    を検出しにくいようにするためである。\r
5034 void CreateDummyValue(PACK *p)\r
5035 {\r
5036         UINT size;\r
5037         UCHAR *buf;\r
5038         // 引数チェック\r
5039         if (p == NULL)\r
5040         {\r
5041                 return;\r
5042         }\r
5043 \r
5044         size = Rand32() % HTTP_PACK_RAND_SIZE_MAX;\r
5045         buf = Malloc(size);\r
5046         Rand(buf, size);\r
5047 \r
5048         PackAddData(p, "pencore", buf, size);\r
5049 \r
5050         Free(buf);\r
5051 }\r
5052 \r
5053 // サーバーがクライアントから PACK を受信する\r
5054 PACK *HttpServerRecv(SOCK *s)\r
5055 {\r
5056         BUF *b;\r
5057         PACK *p;\r
5058         HTTP_HEADER *h;\r
5059         UINT size;\r
5060         UCHAR *tmp;\r
5061         HTTP_VALUE *v;\r
5062         // 引数チェック\r
5063         if (s == NULL)\r
5064         {\r
5065                 return NULL;\r
5066         }\r
5067 \r
5068 START:\r
5069 \r
5070         h = RecvHttpHeader(s);\r
5071         if (h == NULL)\r
5072         {\r
5073                 goto BAD_REQUEST;\r
5074         }\r
5075 \r
5076         if (StrCmpi(h->Method, "POST") != 0 ||\r
5077                 StrCmpi(h->Target, HTTP_VPN_TARGET) != 0 ||\r
5078                 StrCmpi(h->Version, "HTTP/1.1") != 0)\r
5079         {\r
5080                 FreeHttpHeader(h);\r
5081                 goto BAD_REQUEST;\r
5082         }\r
5083 \r
5084         v = GetHttpValue(h, "Content-Type");\r
5085         if (v == NULL || StrCmpi(v->Data, HTTP_CONTENT_TYPE2) != 0)\r
5086         {\r
5087                 FreeHttpHeader(h);\r
5088                 goto BAD_REQUEST;\r
5089         }\r
5090 \r
5091         size = GetContentLength(h);\r
5092         if (size == 0 || size > MAX_PACK_SIZE)\r
5093         {\r
5094                 FreeHttpHeader(h);\r
5095                 goto BAD_REQUEST;\r
5096         }\r
5097 \r
5098         tmp = MallocEx(size, true);\r
5099         if (RecvAll(s, tmp, size, s->SecureMode) == false)\r
5100         {\r
5101                 Free(tmp);\r
5102                 FreeHttpHeader(h);\r
5103                 return NULL;\r
5104         }\r
5105 \r
5106         b = NewBuf();\r
5107         WriteBuf(b, tmp, size);\r
5108         Free(tmp);\r
5109         FreeHttpHeader(h);\r
5110 \r
5111         SeekBuf(b, 0, 0);\r
5112         p = BufToPack(b);\r
5113         FreeBuf(b);\r
5114 \r
5115         // NOOP かどうか判断\r
5116         if (PackGetInt(p, "noop") != 0)\r
5117         {\r
5118                 Debug("recv: noop\n");\r
5119                 FreePack(p);\r
5120 \r
5121                 p = PackError(0);\r
5122                 PackAddInt(p, "noop", 1);\r
5123                 if (HttpServerSend(s, p) == false)\r
5124                 {\r
5125                         FreePack(p);\r
5126                         return NULL;\r
5127                 }\r
5128 \r
5129                 FreePack(p);\r
5130 \r
5131                 goto START;\r
5132         }\r
5133 \r
5134         return p;\r
5135 \r
5136 BAD_REQUEST:\r
5137         // エラーを返す\r
5138 \r
5139 \r
5140         return NULL;\r
5141 }\r
5142 \r
5143 // クライアントがサーバーから PACK を受信する\r
5144 PACK *HttpClientRecv(SOCK *s)\r
5145 {\r
5146         BUF *b;\r
5147         PACK *p;\r
5148         HTTP_HEADER *h;\r
5149         UINT size;\r
5150         UCHAR *tmp;\r
5151         HTTP_VALUE *v;\r
5152         // 引数チェック\r
5153         if (s == NULL)\r
5154         {\r
5155                 return NULL;\r
5156         }\r
5157 \r
5158         h = RecvHttpHeader(s);\r
5159         if (h == NULL)\r
5160         {\r
5161                 return NULL;\r
5162         }\r
5163 \r
5164         if (StrCmpi(h->Method, "HTTP/1.1") != 0 ||\r
5165                 StrCmpi(h->Target, "200") != 0)\r
5166         {\r
5167                 FreeHttpHeader(h);\r
5168                 return NULL;\r
5169         }\r
5170 \r
5171         v = GetHttpValue(h, "Content-Type");\r
5172         if (v == NULL || StrCmpi(v->Data, HTTP_CONTENT_TYPE2) != 0)\r
5173         {\r
5174                 FreeHttpHeader(h);\r
5175                 return NULL;\r
5176         }\r
5177 \r
5178         size = GetContentLength(h);\r
5179         if (size == 0 || size > MAX_PACK_SIZE)\r
5180         {\r
5181                 FreeHttpHeader(h);\r
5182                 return NULL;\r
5183         }\r
5184 \r
5185         tmp = MallocEx(size, true);\r
5186         if (RecvAll(s, tmp, size, s->SecureMode) == false)\r
5187         {\r
5188                 Free(tmp);\r
5189                 FreeHttpHeader(h);\r
5190                 return NULL;\r
5191         }\r
5192 \r
5193         b = NewBuf();\r
5194         WriteBuf(b, tmp, size);\r
5195         Free(tmp);\r
5196         FreeHttpHeader(h);\r
5197 \r
5198         SeekBuf(b, 0, 0);\r
5199         p = BufToPack(b);\r
5200         FreeBuf(b);\r
5201 \r
5202         return p;\r
5203 }\r
5204 \r
5205 // クライアントからサーバーに PACK を送信する\r
5206 bool HttpClientSend(SOCK *s, PACK *p)\r
5207 {\r
5208         BUF *b;\r
5209         bool ret;\r
5210         HTTP_HEADER *h;\r
5211         char date_str[MAX_SIZE];\r
5212         // 引数チェック\r
5213         if (s == NULL || p == NULL)\r
5214         {\r
5215                 return false;\r
5216         }\r
5217 \r
5218         CreateDummyValue(p);\r
5219 \r
5220         b = PackToBuf(p);\r
5221         if (b == NULL)\r
5222         {\r
5223                 return false;\r
5224         }\r
5225 \r
5226         h = NewHttpHeader("POST", HTTP_VPN_TARGET, "HTTP/1.1");\r
5227 \r
5228         GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());\r
5229         AddHttpValue(h, NewHttpValue("Date", date_str));\r
5230         AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));\r
5231         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
5232         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE2));\r
5233 \r
5234         ret = PostHttp(s, h, b->Buf, b->Size);\r
5235 \r
5236         FreeHttpHeader(h);\r
5237         FreeBuf(b);\r
5238 \r
5239         return ret;\r
5240 }\r
5241 \r
5242 // サーバーからクライアントに PACK を送信する\r
5243 bool HttpServerSend(SOCK *s, PACK *p)\r
5244 {\r
5245         BUF *b;\r
5246         bool ret;\r
5247         HTTP_HEADER *h;\r
5248         char date_str[MAX_SIZE];\r
5249         // 引数チェック\r
5250         if (s == NULL || p == NULL)\r
5251         {\r
5252                 return false;\r
5253         }\r
5254 \r
5255         CreateDummyValue(p);\r
5256 \r
5257         b = PackToBuf(p);\r
5258         if (b == NULL)\r
5259         {\r
5260                 return false;\r
5261         }\r
5262 \r
5263         h = NewHttpHeader("HTTP/1.1", "200", "OK");\r
5264 \r
5265         GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());\r
5266         AddHttpValue(h, NewHttpValue("Date", date_str));\r
5267         AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));\r
5268         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
5269         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE2));\r
5270 \r
5271         ret = PostHttp(s, h, b->Buf, b->Size);\r
5272 \r
5273         FreeHttpHeader(h);\r
5274         FreeBuf(b);\r
5275 \r
5276         return ret;\r
5277 }\r
5278 \r
5279 // 501 Not Implemented エラーの送信\r
5280 bool HttpSendNotImplemented(SOCK *s, char *method, char *target, char *version)\r
5281 {\r
5282         HTTP_HEADER *h;\r
5283         char date_str[MAX_SIZE];\r
5284         char *str;\r
5285         UINT str_size;\r
5286         char port_str[MAX_SIZE];\r
5287         bool ret;\r
5288         char host[MAX_SIZE];\r
5289         UINT port;\r
5290         // 引数チェック\r
5291         if (s == NULL || target == NULL)\r
5292         {\r
5293                 return false;\r
5294         }\r
5295 \r
5296         // ホスト名の取得\r
5297         GetMachineName(host, MAX_SIZE);\r
5298         // ポート番号の取得\r
5299         port = s->LocalPort;\r
5300 \r
5301         // ヘッダの作成\r
5302         GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());\r
5303 \r
5304         h = NewHttpHeader("HTTP/1.1", "501", "Method Not Implemented");\r
5305 \r
5306         AddHttpValue(h, NewHttpValue("Date", date_str));\r
5307         AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));\r
5308         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
5309         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));\r
5310 \r
5311         // データの作成\r
5312         str_size = sizeof(http_501_str) * 2 + StrLen(target) + StrLen(host) + StrLen(method) + StrLen(version);\r
5313         str = Malloc(str_size);\r
5314         StrCpy(str, str_size, http_501_str);\r
5315 \r
5316         // TARGET\r
5317         ReplaceStri(str, str_size, str, "$TARGET$", target);\r
5318 \r
5319         // HOST\r
5320         ReplaceStri(str, str_size, str, "$HOST$", host);\r
5321 \r
5322         // PORT\r
5323         ToStr(port_str, port);\r
5324         ReplaceStri(str, str_size, str, "$PORT$", port_str);\r
5325 \r
5326         // METHOD\r
5327         ReplaceStri(str, str_size, str, "$METHOD$", method);\r
5328 \r
5329         // VERSION\r
5330         ReplaceStri(str, str_size, str, "$VERSION$", version);\r
5331 \r
5332         // 送信\r
5333         ret = PostHttp(s, h, str, StrLen(str));\r
5334 \r
5335         FreeHttpHeader(h);\r
5336         Free(str);\r
5337 \r
5338         return ret;\r
5339 }\r
5340 \r
5341 // 404 Not Found エラーの送信\r
5342 bool HttpSendNotFound(SOCK *s, char *target)\r
5343 {\r
5344         HTTP_HEADER *h;\r
5345         char date_str[MAX_SIZE];\r
5346         char *str;\r
5347         UINT str_size;\r
5348         char port_str[MAX_SIZE];\r
5349         bool ret;\r
5350         char host[MAX_SIZE];\r
5351         UINT port;\r
5352         // 引数チェック\r
5353         if (s == NULL || target == NULL)\r
5354         {\r
5355                 return false;\r
5356         }\r
5357 \r
5358         // ホスト名の取得\r
5359         GetMachineName(host, MAX_SIZE);\r
5360         // ポート番号の取得\r
5361         port = s->LocalPort;\r
5362 \r
5363         // ヘッダの作成\r
5364         GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());\r
5365 \r
5366         h = NewHttpHeader("HTTP/1.1", "404", "Not Found");\r
5367 \r
5368         AddHttpValue(h, NewHttpValue("Date", date_str));\r
5369         AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));\r
5370         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
5371         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));\r
5372 \r
5373         // データの作成\r
5374         str_size = sizeof(http_404_str) * 2 + StrLen(target) + StrLen(host);\r
5375         str = Malloc(str_size);\r
5376         StrCpy(str, str_size, http_404_str);\r
5377 \r
5378         // TARGET\r
5379         ReplaceStri(str, str_size, str, "$TARGET$", target);\r
5380 \r
5381         // HOST\r
5382         ReplaceStri(str, str_size, str, "$HOST$", host);\r
5383 \r
5384         // PORT\r
5385         ToStr(port_str, port);\r
5386         ReplaceStri(str, str_size, str, "$PORT$", port_str);\r
5387 \r
5388         // 送信\r
5389         ret = PostHttp(s, h, str, StrLen(str));\r
5390 \r
5391         FreeHttpHeader(h);\r
5392         Free(str);\r
5393 \r
5394         return ret;\r
5395 }\r
5396 \r
5397 // 403 Forbidden エラーの送信\r
5398 bool HttpSendForbidden(SOCK *s, char *target, char *server_id)\r
5399 {\r
5400         HTTP_HEADER *h;\r
5401         char date_str[MAX_SIZE];\r
5402         char *str;\r
5403         UINT str_size;\r
5404         char port_str[MAX_SIZE];\r
5405         bool ret;\r
5406         char host[MAX_SIZE];\r
5407         UINT port;\r
5408         // 引数チェック\r
5409         if (s == NULL || target == NULL)\r
5410         {\r
5411                 return false;\r
5412         }\r
5413 \r
5414         // ホスト名の取得\r
5415         GetMachineName(host, MAX_SIZE);\r
5416         // ポート番号の取得\r
5417         port = s->LocalPort;\r
5418 \r
5419         // ヘッダの作成\r
5420         GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());\r
5421 \r
5422         h = NewHttpHeader("HTTP/1.1", "403", "Forbidden");\r
5423 \r
5424         AddHttpValue(h, NewHttpValue("Date", date_str));\r
5425         AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));\r
5426         AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));\r
5427         AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));\r
5428 \r
5429         // データの作成\r
5430         str_size = sizeof(http_403_str) * 2 + StrLen(target) + StrLen(host);\r
5431         str = Malloc(str_size);\r
5432         StrCpy(str, str_size, http_403_str);\r
5433 \r
5434         // TARGET\r
5435         ReplaceStri(str, str_size, str, "$TARGET$", target);\r
5436 \r
5437         // HOST\r
5438         ReplaceStri(str, str_size, str, "$HOST$", host);\r
5439 \r
5440         // PORT\r
5441         ToStr(port_str, port);\r
5442         ReplaceStri(str, str_size, str, "$PORT$", port_str);\r
5443 \r
5444         // 送信\r
5445         ret = PostHttp(s, h, str, StrLen(str));\r
5446 \r
5447         FreeHttpHeader(h);\r
5448         Free(str);\r
5449 \r
5450         return ret;\r
5451 }\r
5452 \r
5453 // HTTP ヘッダ用の日時文字列を取得\r
5454 void GetHttpDateStr(char *str, UINT size, UINT64 t)\r
5455 {\r
5456         SYSTEMTIME s;\r
5457         static char *wday[] =\r
5458         {\r
5459                 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",\r
5460         };\r
5461         static char *month[] =\r
5462         {\r
5463                 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",\r
5464                 "Nov", "Dec",\r
5465         };\r
5466         // 引数チェック\r
5467         if (str == NULL)\r
5468         {\r
5469                 return;\r
5470         }\r
5471         UINT64ToSystem(&s, t);\r
5472 \r
5473         Format(str, size, "%s, %02u %s %04u %02u:%02u:%02u GMT",\r
5474                 wday[s.wDayOfWeek], s.wDay, month[s.wMonth - 1], s.wYear,\r
5475                 s.wHour, s.wMinute, s.wSecond);\r
5476 }\r
5477 \r
5478 // HTTP ヘッダからコンテンツ長を取得する\r
5479 UINT GetContentLength(HTTP_HEADER *header)\r
5480 {\r
5481         UINT ret;\r
5482         HTTP_VALUE *v;\r
5483         // 引数チェック\r
5484         if (header == NULL)\r
5485         {\r
5486                 return 0;\r
5487         }\r
5488 \r
5489         v = GetHttpValue(header, "Content-Length");\r
5490         if (v == NULL)\r
5491         {\r
5492                 return 0;\r
5493         }\r
5494 \r
5495         ret = ToInt(v->Data);\r
5496 \r
5497         return ret;\r
5498 }\r
5499 \r
5500 // HTTP でデータを送信する\r
5501 bool PostHttp(SOCK *s, HTTP_HEADER *header, void *post_data, UINT post_size)\r
5502 {\r
5503         char *header_str;\r
5504         BUF *b;\r
5505         bool ret;\r
5506         // 引数チェック\r
5507         if (s == NULL || header == NULL || post_data == NULL)\r
5508         {\r
5509                 return false;\r
5510         }\r
5511 \r
5512         // Content-Lentgh が存在するかどうかチェック\r
5513         if (GetHttpValue(header, "Content-Length") == NULL)\r
5514         {\r
5515                 char tmp[MAX_SIZE];\r
5516                 // 存在しないので付加する\r
5517                 ToStr(tmp, post_size);\r
5518                 AddHttpValue(header, NewHttpValue("Content-Length", tmp));\r
5519         }\r
5520 \r
5521         // ヘッダを文字列にする\r
5522         header_str = HttpHeaderToStr(header);\r
5523         if (header_str == NULL)\r
5524         {\r
5525                 return false;\r
5526         }\r
5527         b = NewBuf();\r
5528         WriteBuf(b, header_str, StrLen(header_str));\r
5529         Free(header_str);\r
5530 \r
5531         // データを追記する\r
5532         WriteBuf(b, post_data, post_size);\r
5533 \r
5534         // 送信する\r
5535         ret = SendAll(s, b->Buf, b->Size, s->SecureMode);\r
5536 \r
5537         FreeBuf(b);\r
5538 \r
5539         return ret;\r
5540 }\r
5541 \r
5542 // HTTP ヘッダを文字列に変換\r
5543 char *HttpHeaderToStr(HTTP_HEADER *header)\r
5544 {\r
5545         BUF *b;\r
5546         char *tmp;\r
5547         UINT i;\r
5548         char *s;\r
5549         // 引数チェック\r
5550         if (header == NULL)\r
5551         {\r
5552                 return NULL;\r
5553         }\r
5554 \r
5555         tmp = Malloc(HTTP_HEADER_LINE_MAX_SIZE);\r
5556         b = NewBuf();\r
5557 \r
5558         // ヘッダ\r
5559         Format(tmp, HTTP_HEADER_LINE_MAX_SIZE,\r
5560                 "%s %s %s\r\n", header->Method, header->Target, header->Version);\r
5561         WriteBuf(b, tmp, StrLen(tmp));\r
5562 \r
5563         // 値\r
5564         for (i = 0;i < LIST_NUM(header->ValueList);i++)\r
5565         {\r
5566                 HTTP_VALUE *v = (HTTP_VALUE *)LIST_DATA(header->ValueList, i);\r
5567                 Format(tmp, HTTP_HEADER_LINE_MAX_SIZE,\r
5568                         "%s: %s\r\n", v->Name, v->Data);\r
5569                 WriteBuf(b, tmp, StrLen(tmp));\r
5570         }\r
5571 \r
5572         // 最後の改行\r
5573         WriteBuf(b, "\r\n", 2);\r
5574         s = Malloc(b->Size + 1);\r
5575         Copy(s, b->Buf, b->Size);\r
5576         s[b->Size] = 0;\r
5577 \r
5578         FreeBuf(b);\r
5579         Free(tmp);\r
5580 \r
5581         return s;\r
5582 }\r
5583 \r
5584 // HTTP ヘッダを送信\r
5585 bool SendHttpHeader(SOCK *s, HTTP_HEADER *header)\r
5586 {\r
5587         char *str;\r
5588         bool ret;\r
5589         // 引数チェック\r
5590         if (s == NULL || header == NULL)\r
5591         {\r
5592                 return false;\r
5593         }\r
5594 \r
5595         // 文字列に変換\r
5596         str = HttpHeaderToStr(header);\r
5597 \r
5598         // 送信\r
5599         ret = SendAll(s, str, StrLen(str), s->SecureMode);\r
5600 \r
5601         Free(str);\r
5602 \r
5603         return ret;\r
5604 }\r
5605 \r
5606 // HTTP ヘッダを受信\r
5607 HTTP_HEADER *RecvHttpHeader(SOCK *s)\r
5608 {\r
5609         TOKEN_LIST *token = NULL;\r
5610         char *str = NULL;\r
5611         HTTP_HEADER *header = NULL;\r
5612         // 引数チェック\r
5613         if (s == NULL)\r
5614         {\r
5615                 return NULL;\r
5616         }\r
5617 \r
5618         // 1 行目を取得する\r
5619         str = RecvLine(s, HTTP_HEADER_LINE_MAX_SIZE);\r
5620         if (str == NULL)\r
5621         {\r
5622                 goto ERROR;\r
5623         }\r
5624 \r
5625         // トークンに分割する\r
5626         token = ParseToken(str, " ");\r
5627         if (token->NumTokens < 3)\r
5628         {\r
5629                 goto ERROR;\r
5630         }\r
5631 \r
5632         Free(str);\r
5633         str = NULL;\r
5634 \r
5635         // ヘッダの作成\r
5636         header = NewHttpHeader(token->Token[0], token->Token[1], token->Token[2]);\r
5637 \r
5638         if (!StrCmpi(header->Version, "HTTP/1.0") || !StrCmpi(header->Version, "HTTP/0.9"))\r
5639         {\r
5640                 // この行で終わり\r
5641                 return header;\r
5642         }\r
5643 \r
5644         // 2 行目以降を取得する\r
5645         while (true)\r
5646         {\r
5647                 UINT pos;\r
5648                 HTTP_VALUE *v;\r
5649                 char *value_name, *value_data;\r
5650                 str = RecvLine(s, HTTP_HEADER_LINE_MAX_SIZE);\r
5651                 if (str == NULL)\r
5652                 {\r
5653                         goto ERROR;\r
5654                 }\r
5655                 Trim(str);\r
5656 \r
5657                 if (StrLen(str) == 0)\r
5658                 {\r
5659                         // ヘッダの終了\r
5660                         Free(str);\r
5661                         str = NULL;\r
5662                         break;\r
5663                 }\r
5664 \r
5665                 // コロンの位置を取得する\r
5666                 pos = SearchStr(str, ":", 0);\r
5667                 if (pos == INFINITE)\r
5668                 {\r
5669                         // コロンが存在しない\r
5670                         goto ERROR;\r
5671                 }\r
5672                 if ((pos + 1) >= StrLen(str))\r
5673                 {\r
5674                         // データが存在しない\r
5675                         goto ERROR;\r
5676                 }\r
5677 \r
5678                 // 名前とデータの 2 つに分ける\r
5679                 value_name = Malloc(pos + 1);\r
5680                 Copy(value_name, str, pos);\r
5681                 value_name[pos] = 0;\r
5682                 value_data = &str[pos + 1];\r
5683 \r
5684                 v = NewHttpValue(value_name, value_data);\r
5685                 if (v == NULL)\r
5686                 {\r
5687                         Free(value_name);\r
5688                         goto ERROR;\r
5689                 }\r
5690 \r
5691                 Free(value_name);\r
5692 \r
5693                 AddHttpValue(header, v);\r
5694                 Free(str);\r
5695         }\r
5696 \r
5697         FreeToken(token);\r
5698 \r
5699         return header;\r
5700 \r
5701 ERROR:\r
5702         // メモリ解放\r
5703         if (token)\r
5704         {\r
5705                 FreeToken(token);\r
5706         }\r
5707         if (str)\r
5708         {\r
5709                 Free(str);\r
5710         }\r
5711         if (header)\r
5712         {\r
5713                 FreeHttpHeader(header);\r
5714         }\r
5715         return NULL;\r
5716 }\r
5717 \r
5718 // 1 行を受信する\r
5719 char *RecvLine(SOCK *s, UINT max_size)\r
5720 {\r
5721         BUF *b;\r
5722         char c;\r
5723         char *str;\r
5724         // 引数チェック\r
5725         if (s == NULL || max_size == 0)\r
5726         {\r
5727                 return NULL;\r
5728         }\r
5729 \r
5730         b = NewBuf();\r
5731         while (true)\r
5732         {\r
5733                 UCHAR *buf;\r
5734                 if (RecvAll(s, &c, sizeof(c), s->SecureMode) == false)\r
5735                 {\r
5736                         FreeBuf(b);\r
5737                         return NULL;\r
5738                 }\r
5739                 WriteBuf(b, &c, sizeof(c));\r
5740                 buf = (UCHAR *)b->Buf;\r
5741                 if (b->Size > max_size)\r
5742                 {\r
5743                         FreeBuf(b);\r
5744                         return NULL;\r
5745                 }\r
5746                 if (b->Size >= 1)\r
5747                 {\r
5748                         if (buf[b->Size - 1] == '\n')\r
5749                         {\r
5750                                 b->Size--;\r
5751                                 if (b->Size >= 1)\r
5752                                 {\r
5753                                         if (buf[b->Size - 1] == '\r')\r
5754                                         {\r
5755                                                 b->Size--;\r
5756                                         }\r
5757                                 }\r
5758                                 str = Malloc(b->Size + 1);\r
5759                                 Copy(str, b->Buf, b->Size);\r
5760                                 str[b->Size] = 0;\r
5761                                 FreeBuf(b);\r
5762 \r
5763                                 return str;\r
5764                         }\r
5765                 }\r
5766         }\r
5767 }\r
5768 \r
5769 // 新しい HTTP 値の作成\r
5770 HTTP_VALUE *NewHttpValue(char *name, char *data)\r
5771 {\r
5772         HTTP_VALUE *v;\r
5773         // 引数チェック\r
5774         if (name == NULL || data == NULL)\r
5775         {\r
5776                 return NULL;\r
5777         }\r
5778 \r
5779         v = ZeroMalloc(sizeof(HTTP_VALUE));\r
5780 \r
5781         v->Name = CopyStr(name);\r
5782         v->Data = CopyStr(data);\r
5783 \r
5784         Trim(v->Name);\r
5785         Trim(v->Data);\r
5786 \r
5787         return v;\r
5788 }\r
5789 \r
5790 // プロトコルルーチンの初期化\r
5791 void InitProtocol()\r
5792 {\r
5793 }\r
5794 \r
5795 // プロトコルルーチンの解放\r
5796 void FreeProtocol()\r
5797 {\r
5798 }\r
5799 \r
5800 // HTTP ヘッダから HTTP 値を探す\r
5801 HTTP_VALUE *GetHttpValue(HTTP_HEADER *header, char *name)\r
5802 {\r
5803         HTTP_VALUE *v, t;\r
5804         // 引数チェック\r
5805         if (header == NULL || name == NULL)\r
5806         {\r
5807                 return NULL;\r
5808         }\r
5809 \r
5810         t.Name = name;\r
5811         v = Search(header->ValueList, &t);\r
5812         if (v == NULL)\r
5813         {\r
5814                 return NULL;\r
5815         }\r
5816 \r
5817         return v;\r
5818 }\r
5819 \r
5820 // HTTP ヘッダに HTTP 値を追加\r
5821 void AddHttpValue(HTTP_HEADER *header, HTTP_VALUE *value)\r
5822 {\r
5823         // 引数チェック\r
5824         if (header == NULL || value == NULL)\r
5825         {\r
5826                 return;\r
5827         }\r
5828 \r
5829         Insert(header->ValueList, value);\r
5830 }\r
5831 \r
5832 // HTTP ヘッダを作成\r
5833 HTTP_HEADER *NewHttpHeader(char *method, char *target, char *version)\r
5834 {\r
5835         HTTP_HEADER *header;\r
5836         // 引数チェック\r
5837         if (method == NULL || target == NULL || version == NULL)\r
5838         {\r
5839                 return NULL;\r
5840         }\r
5841 \r
5842         header = ZeroMalloc(sizeof(HTTP_HEADER));\r
5843 \r
5844         header->Method = CopyStr(method);\r
5845         header->Target = CopyStr(target);\r
5846         header->Version = CopyStr(version);\r
5847         header->ValueList = NewListFast(CompareHttpValue);\r
5848 \r
5849         return header;\r
5850 }\r
5851 \r
5852 // HTTP 値の比較関数\r
5853 int CompareHttpValue(void *p1, void *p2)\r
5854 {\r
5855         HTTP_VALUE *v1, *v2;\r
5856         if (p1 == NULL || p2 == NULL)\r
5857         {\r
5858                 return 0;\r
5859         }\r
5860         v1 = *(HTTP_VALUE **)p1;\r
5861         v2 = *(HTTP_VALUE **)p2;\r
5862         if (v1 == NULL || v2 == NULL)\r
5863         {\r
5864                 return 0;\r
5865         }\r
5866         return StrCmpi(v1->Name, v2->Name);\r
5867 }\r
5868 \r
5869 // HTTP 値を解放\r
5870 void FreeHttpValue(HTTP_VALUE *value)\r
5871 {\r
5872         // 引数チェック\r
5873         if (value == NULL)\r
5874         {\r
5875                 return;\r
5876         }\r
5877 \r
5878         Free(value->Data);\r
5879         Free(value->Name);\r
5880 \r
5881         Free(value);\r
5882 }\r
5883 \r
5884 // HTTP ヘッダを解放\r
5885 void FreeHttpHeader(HTTP_HEADER *header)\r
5886 {\r
5887         UINT i;\r
5888         HTTP_VALUE **values;\r
5889         // 引数チェック\r
5890         if (header == NULL)\r
5891         {\r
5892                 return;\r
5893         }\r
5894 \r
5895         Free(header->Method);\r
5896         Free(header->Target);\r
5897         Free(header->Version);\r
5898 \r
5899         values = ToArray(header->ValueList);\r
5900         for (i = 0;i < LIST_NUM(header->ValueList);i++)\r
5901         {\r
5902                 FreeHttpValue(values[i]);\r
5903         }\r
5904         Free(values);\r
5905 \r
5906         ReleaseList(header->ValueList);\r
5907 \r
5908         Free(header);\r
5909 }\r
5910 \r
5911 // パケットを受信\r
5912 PACK *RecvPack(SOCK *s)\r
5913 {\r
5914         PACK *p;\r
5915         BUF *b;\r
5916         void *data;\r
5917         UINT sz;\r
5918         // 引数チェック\r
5919         if (s == NULL || s->Type != SOCK_TCP)\r
5920         {\r
5921                 return false;\r
5922         }\r
5923 \r
5924         if (RecvAll(s, &sz, sizeof(UINT), s->SecureMode) == false)\r
5925         {\r
5926                 return false;\r
5927         }\r
5928         sz = Endian32(sz);\r
5929         if (sz > MAX_PACK_SIZE)\r
5930         {\r
5931                 return false;\r
5932         }\r
5933         data = MallocEx(sz, true);\r
5934         if (RecvAll(s, data, sz, s->SecureMode) == false)\r
5935         {\r
5936                 Free(data);\r
5937                 return false;\r
5938         }\r
5939 \r
5940         b = NewBuf();\r
5941         WriteBuf(b, data, sz);\r
5942         SeekBuf(b, 0, 0);\r
5943         p = BufToPack(b);\r
5944         FreeBuf(b);\r
5945         Free(data);\r
5946 \r
5947         return p;\r
5948 }\r
5949 \r
5950 // パケットを送信\r
5951 bool SendPack(SOCK *s, PACK *p)\r
5952 {\r
5953         BUF *b;\r
5954         UINT sz;\r
5955         // 引数チェック\r
5956         if (s == NULL || p == NULL || s->Type != SOCK_TCP)\r
5957         {\r
5958                 return false;\r
5959         }\r
5960 \r
5961         b = PackToBuf(p);\r
5962         sz = Endian32(b->Size);\r
5963 \r
5964         SendAdd(s, &sz, sizeof(UINT));\r
5965         SendAdd(s, b->Buf, b->Size);\r
5966         FreeBuf(b);\r
5967 \r
5968         return SendNow(s, s->SecureMode);\r
5969 }\r
5970 \r
5971 // Hello パケットを作成\r
5972 PACK *PackHello(void *random, UINT ver, UINT build, char *server_str)\r
5973 {\r
5974         PACK *p;\r
5975         // 引数チェック\r
5976         if (random == NULL || server_str == NULL)\r
5977         {\r
5978                 return NULL;\r
5979         }\r
5980 \r
5981         p = NewPack();\r
5982         PackAddStr(p, "hello", server_str);\r
5983         PackAddInt(p, "version", ver);\r
5984         PackAddInt(p, "build", build);\r
5985         PackAddData(p, "random", random, SHA1_SIZE);\r
5986 \r
5987         return p;\r
5988 }\r
5989 \r
5990 // Hello パケットを解釈\r
5991 bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size)\r
5992 {\r
5993         // 引数チェック\r
5994         if (p == NULL || random == NULL || ver == NULL || server_str == NULL)\r
5995         {\r
5996                 return false;\r
5997         }\r
5998 \r
5999         if (PackGetStr(p, "hello", server_str, server_str_size) == false)\r
6000         {\r
6001                 return false;\r
6002         }\r
6003         *ver = PackGetInt(p, "version");\r
6004         *build = PackGetInt(p, "build");\r
6005         if (PackGetDataSize(p, "random") != SHA1_SIZE)\r
6006         {\r
6007                 return false;\r
6008         }\r
6009         if (PackGetData(p, "random", random) == false)\r
6010         {\r
6011                 return false;\r
6012         }\r
6013 \r
6014         return true;\r
6015 }\r
6016 \r
6017 // エラー値を PACK に格納\r
6018 PACK *PackError(UINT error)\r
6019 {\r
6020         PACK *p;\r
6021 \r
6022         p = NewPack();\r
6023         PackAddInt(p, "error", error);\r
6024 \r
6025         return p;\r
6026 }\r
6027 \r
6028 // エラー値を PACK から取得\r
6029 UINT GetErrorFromPack(PACK *p)\r
6030 {\r
6031         // 引数チェック\r
6032         if (p == NULL)\r
6033         {\r
6034                 return 0;\r
6035         }\r
6036 \r
6037         return PackGetInt(p, "error");\r
6038 }\r
6039 \r
6040 // 認証方法を PACK から取得\r
6041 UINT GetAuthTypeFromPack(PACK *p)\r
6042 {\r
6043         // 引数チェック\r
6044         if (p == NULL)\r
6045         {\r
6046                 return 0;\r
6047         }\r
6048 \r
6049         return PackGetInt(p, "authtype");\r
6050 }\r
6051 \r
6052 // ユーザー名と HUB 名を PACK から取得\r
6053 bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,\r
6054                                                                    char *hubname, UINT hubname_size)\r
6055 {\r
6056         // 引数チェック\r
6057         if (p == NULL || username == NULL || hubname == NULL)\r
6058         {\r
6059                 return false;\r
6060         }\r
6061 \r
6062         if (PackGetStr(p, "username", username, username_size) == false)\r
6063         {\r
6064                 return false;\r
6065         }\r
6066         if (PackGetStr(p, "hubname", hubname, hubname_size) == false)\r
6067         {\r
6068                 return false;\r
6069         }\r
6070         return true;\r
6071 }\r
6072 \r
6073 // プロトコルを PACK から取得\r
6074 UINT GetProtocolFromPack(PACK *p)\r
6075 {\r
6076         // 引数チェック\r
6077         if (p == NULL)\r
6078         {\r
6079                 return 0;\r
6080         }\r
6081 \r
6082 #if     0\r
6083         return PackGetInt(p, "protocol");\r
6084 #else\r
6085         // 現バージョンでは TCP プロトコルに限定する\r
6086         return CONNECTION_TCP;\r
6087 #endif\r
6088 }\r
6089 \r
6090 // メソッドを PACK から取得\r
6091 bool GetMethodFromPack(PACK *p, char *method, UINT size)\r
6092 {\r
6093         // 引数チェック\r
6094         if (p == NULL || method == NULL || size == 0)\r
6095         {\r
6096                 return false;\r
6097         }\r
6098 \r
6099         return PackGetStr(p, "method", method, size);\r
6100 }\r
6101 \r
6102 // 証明書認証ログイン用のパケットを生成\r
6103 PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size)\r
6104 {\r
6105         PACK *p;\r
6106         BUF *b;\r
6107         // 引数チェック\r
6108         if (hubname == NULL || username == NULL)\r
6109         {\r
6110                 return NULL;\r
6111         }\r
6112 \r
6113         p = NewPack();\r
6114         PackAddStr(p, "method", "login");\r
6115         PackAddStr(p, "hubname", hubname);\r
6116         PackAddStr(p, "username", username);\r
6117         PackAddInt(p, "authtype", CLIENT_AUTHTYPE_CERT);\r
6118 \r
6119         // 証明書\r
6120         b = XToBuf(x, false);\r
6121         PackAddData(p, "cert", b->Buf, b->Size);\r
6122         FreeBuf(b);\r
6123 \r
6124         // 署名データ\r
6125         PackAddData(p, "sign", sign, sign_size);\r
6126 \r
6127         return p;\r
6128 }\r
6129 \r
6130 // 平文パスワード認証ログイン用のパケットを生成\r
6131 PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password)\r
6132 {\r
6133         PACK *p;\r
6134         // 引数チェック\r
6135         if (hubname == NULL || username == NULL)\r
6136         {\r
6137                 return NULL;\r
6138         }\r
6139 \r
6140         p = NewPack();\r
6141         PackAddStr(p, "method", "login");\r
6142         PackAddStr(p, "hubname", hubname);\r
6143         PackAddStr(p, "username", username);\r
6144         PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PLAIN_PASSWORD);\r
6145         PackAddStr(p, "plain_password", plain_password);\r
6146 \r
6147         return p;\r
6148 }\r
6149 \r
6150 // パスワード認証ログイン用のパケットを作成\r
6151 PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password)\r
6152 {\r
6153         PACK *p;\r
6154         // 引数チェック\r
6155         if (hubname == NULL || username == NULL)\r
6156         {\r
6157                 return NULL;\r
6158         }\r
6159 \r
6160         p = NewPack();\r
6161         PackAddStr(p, "method", "login");\r
6162         PackAddStr(p, "hubname", hubname);\r
6163         PackAddStr(p, "username", username);\r
6164         PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PASSWORD);\r
6165         PackAddData(p, "secure_password", secure_password, SHA1_SIZE);\r
6166 \r
6167         return p;\r
6168 }\r
6169 \r
6170 // 匿名ログイン用のパケットを作成\r
6171 PACK *PackLoginWithAnonymous(char *hubname, char *username)\r
6172 {\r
6173         PACK *p;\r
6174         // 引数チェック\r
6175         if (hubname == NULL || username == NULL)\r
6176         {\r
6177                 return NULL;\r
6178         }\r
6179 \r
6180         p = NewPack();\r
6181         PackAddStr(p, "method", "login");\r
6182         PackAddStr(p, "hubname", hubname);\r
6183         PackAddStr(p, "username", username);\r
6184         PackAddInt(p, "authtype", CLIENT_AUTHTYPE_ANONYMOUS);\r
6185 \r
6186         return p;\r
6187 }\r
6188 \r
6189 // 追加接続用のパケットを作成\r
6190 PACK *PackAdditionalConnect(UCHAR *session_key)\r
6191 {\r
6192         PACK *p;\r
6193         // 引数チェック\r
6194         if (session_key == NULL)\r
6195         {\r
6196                 return NULL;\r
6197         }\r
6198 \r
6199         p = NewPack();\r
6200         PackAddStr(p, "method", "additional_connect");\r
6201         PackAddData(p, "session_key", session_key, SHA1_SIZE);\r
6202 \r
6203         return p;\r
6204 }\r
6205 \r
6206 // PACK から K を取得\r
6207 K *PackGetK(PACK *p, char *name)\r
6208 {\r
6209         K *k;\r
6210         BUF *b;\r
6211         // 引数チェック\r
6212         if (p == NULL || name == NULL)\r
6213         {\r
6214                 return NULL;\r
6215         }\r
6216 \r
6217         b = PackGetBuf(p, name);\r
6218         if (b == NULL)\r
6219         {\r
6220                 return NULL;\r
6221         }\r
6222 \r
6223         k = BufToK(b, true, false, NULL);\r
6224         FreeBuf(b);\r
6225 \r
6226         return k;\r
6227 }\r
6228 \r
6229 // PACK から X を取得\r
6230 X *PackGetX(PACK *p, char *name)\r
6231 {\r
6232         X *x;\r
6233         BUF *b;\r
6234         // 引数チェック\r
6235         if (p == NULL || name == NULL)\r
6236         {\r
6237                 return NULL;\r
6238         }\r
6239 \r
6240         b = PackGetBuf(p, name);\r
6241         if (b == NULL)\r
6242         {\r
6243                 return NULL;\r
6244         }\r
6245 \r
6246         x = BufToX(b, false);\r
6247         FreeBuf(b);\r
6248 \r
6249         return x;\r
6250 }\r
6251 \r
6252 // PACK に K を追加\r
6253 void PackAddK(PACK *p, char *name, K *k)\r
6254 {\r
6255         BUF *b;\r
6256         // 引数チェック\r
6257         if (p == NULL || name == NULL || k == NULL)\r
6258         {\r
6259                 return;\r
6260         }\r
6261 \r
6262         b = KToBuf(k, false, NULL);\r
6263         if (b == NULL)\r
6264         {\r
6265                 return;\r
6266         }\r
6267 \r
6268         PackAddBuf(p, name, b);\r
6269         FreeBuf(b);\r
6270 }\r
6271 \r
6272 // PACK に X を追加\r
6273 void PackAddX(PACK *p, char *name, X *x)\r
6274 {\r
6275         BUF *b;\r
6276         // 引数チェック\r
6277         if (p == NULL || name == NULL || x == NULL)\r
6278         {\r
6279                 return;\r
6280         }\r
6281 \r
6282         b = XToBuf(x, false);\r
6283         if (b == NULL)\r
6284         {\r
6285                 return;\r
6286         }\r
6287 \r
6288         PackAddBuf(p, name, b);\r
6289         FreeBuf(b);\r
6290 }\r
6291 \r
6292 // PACK からバッファを取得\r
6293 BUF *PackGetBuf(PACK *p, char *name)\r
6294 {\r
6295         return PackGetBufEx(p, name, 0);\r
6296 }\r
6297 BUF *PackGetBufEx(PACK *p, char *name, UINT index)\r
6298 {\r
6299         UINT size;\r
6300         void *tmp;\r
6301         BUF *b;\r
6302         // 引数チェック\r
6303         if (p == NULL || name == NULL)\r
6304         {\r
6305                 return NULL;\r
6306         }\r
6307 \r
6308         size = PackGetDataSizeEx(p, name, index);\r
6309         tmp = MallocEx(size, true);\r
6310         if (PackGetDataEx(p, name, tmp, index) == false)\r
6311         {\r
6312                 Free(tmp);\r
6313                 return NULL;\r
6314         }\r
6315 \r
6316         b = NewBuf();\r
6317         WriteBuf(b, tmp, size);\r
6318         SeekBuf(b, 0, 0);\r
6319 \r
6320         Free(tmp);\r
6321 \r
6322         return b;\r
6323 }\r
6324 \r
6325 // PACK からデータを取得\r
6326 bool PackGetData(PACK *p, char *name, void *data)\r
6327 {\r
6328         return PackGetDataEx(p, name, data, 0);\r
6329 }\r
6330 bool PackGetDataEx(PACK *p, char *name, void *data, UINT index)\r
6331 {\r
6332         ELEMENT *e;\r
6333         // 引数チェック\r
6334         if (p == NULL || name == NULL)\r
6335         {\r
6336                 return false;\r
6337         }\r
6338 \r
6339         e = GetElement(p, name, VALUE_DATA);\r
6340         if (e == NULL)\r
6341         {\r
6342                 return false;\r
6343         }\r
6344         Copy(data, GetDataValue(e, index), GetDataValueSize(e, index));\r
6345         return true;\r
6346 }\r
6347 bool PackGetData2(PACK *p, char *name, void *data, UINT size)\r
6348 {\r
6349         return PackGetDataEx2(p, name, data, size, 0);\r
6350 }\r
6351 bool PackGetDataEx2(PACK *p, char *name, void *data, UINT size, UINT index)\r
6352 {\r
6353         ELEMENT *e;\r
6354         // 引数チェック\r
6355         if (p == NULL || name == NULL)\r
6356         {\r
6357                 return false;\r
6358         }\r
6359 \r
6360         e = GetElement(p, name, VALUE_DATA);\r
6361         if (e == NULL)\r
6362         {\r
6363                 return false;\r
6364         }\r
6365         if (GetDataValueSize(e, index) != size)\r
6366         {\r
6367                 return false;\r
6368         }\r
6369         Copy(data, GetDataValue(e, index), GetDataValueSize(e, index));\r
6370         return true;\r
6371 }\r
6372 \r
6373 // PACK からデータサイズを取得\r
6374 UINT PackGetDataSize(PACK *p, char *name)\r
6375 {\r
6376         return PackGetDataSizeEx(p, name, 0);\r
6377 }\r
6378 UINT PackGetDataSizeEx(PACK *p, char *name, UINT index)\r
6379 {\r
6380         ELEMENT *e;\r
6381         // 引数チェック\r
6382         if (p == NULL || name == NULL)\r
6383         {\r
6384                 return 0;\r
6385         }\r
6386 \r
6387         e = GetElement(p, name, VALUE_DATA);\r
6388         if (e == NULL)\r
6389         {\r
6390                 return 0;\r
6391         }\r
6392         return GetDataValueSize(e, index);\r
6393 }\r
6394 \r
6395 // PACK から整数を取得\r
6396 UINT64 PackGetInt64(PACK *p, char *name)\r
6397 {\r
6398         return PackGetInt64Ex(p, name, 0);\r
6399 }\r
6400 UINT64 PackGetInt64Ex(PACK *p, char *name, UINT index)\r
6401 {\r
6402         ELEMENT *e;\r
6403         // 引数チェック\r
6404         if (p == NULL || name == NULL)\r
6405         {\r
6406                 return 0;\r
6407         }\r
6408 \r
6409         e = GetElement(p, name, VALUE_INT64);\r
6410         if (e == NULL)\r
6411         {\r
6412                 return 0;\r
6413         }\r
6414         return GetInt64Value(e, index);\r
6415 }\r
6416 \r
6417 // PACK からインデックス数を取得\r
6418 UINT PackGetIndexCount(PACK *p, char *name)\r
6419 {\r
6420         ELEMENT *e;\r
6421         // 引数チェック\r
6422         if (p == NULL || name == NULL)\r
6423         {\r
6424                 return 0;\r
6425         }\r
6426 \r
6427         e = GetElement(p, name, INFINITE);\r
6428         if (e == NULL)\r
6429         {\r
6430                 return 0;\r
6431         }\r
6432 \r
6433         return e->num_value;\r
6434 }\r
6435 \r
6436 // PACK から個数を取得\r
6437 UINT PackGetNum(PACK *p, char *name)\r
6438 {\r
6439         return MIN(PackGetInt(p, name), 65536);\r
6440 }\r
6441 \r
6442 // PACK から bool 型を取得\r
6443 bool PackGetBool(PACK *p, char *name)\r
6444 {\r
6445         return PackGetInt(p, name) == 0 ? false : true;\r
6446 }\r
6447 bool PackGetBoolEx(PACK *p, char *name, UINT index)\r
6448 {\r
6449         return PackGetIntEx(p, name, index) == 0 ? false : true;\r
6450 }\r
6451 \r
6452 // PACK に bool 型を追加\r
6453 void PackAddBool(PACK *p, char *name, bool b)\r
6454 {\r
6455         PackAddInt(p, name, b ? 1 : 0);\r
6456 }\r
6457 void PackAddBoolEx(PACK *p, char *name, bool b, UINT index, UINT total)\r
6458 {\r
6459         PackAddIntEx(p, name, b ? 1 : 0, index, total);\r
6460 }\r
6461 \r
6462 // PACK に IPV6_ADDR を追加\r
6463 void PackAddIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index, UINT total)\r
6464 {\r
6465         // 引数チェック\r
6466         if (p == NULL || name == NULL || addr == NULL)\r
6467         {\r
6468                 return;\r
6469         }\r
6470 \r
6471         PackAddDataEx(p, name, addr, sizeof(IPV6_ADDR), index, total);\r
6472 }\r
6473 void PackAddIp6Addr(PACK *p, char *name, IPV6_ADDR *addr)\r
6474 {\r
6475         PackAddIp6AddrEx(p, name, addr, 0, 1);\r
6476 }\r
6477 \r
6478 // PACK から IPV6_ADDR を取得\r
6479 bool PackGetIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index)\r
6480 {\r
6481         // 引数チェック\r
6482         if (p == NULL || name == NULL || addr == NULL)\r
6483         {\r
6484                 Zero(addr, sizeof(IPV6_ADDR));\r
6485                 return false;\r
6486         }\r
6487 \r
6488         return PackGetDataEx2(p, name, addr, sizeof(IPV6_ADDR), index);\r
6489 }\r
6490 bool PackGetIp6Addr(PACK *p, char *name, IPV6_ADDR *addr)\r
6491 {\r
6492         return PackGetIp6AddrEx(p, name, addr, 0);\r
6493 }\r
6494 \r
6495 // PACK に IP を追加\r
6496 void PackAddIp32Ex(PACK *p, char *name, UINT ip32, UINT index, UINT total)\r
6497 {\r
6498         IP ip;\r
6499         // 引数チェック\r
6500         if (p == NULL || name == NULL)\r
6501         {\r
6502                 return;\r
6503         }\r
6504 \r
6505         UINTToIP(&ip, ip32);\r
6506 \r
6507         PackAddIpEx(p, name, &ip, index, total);\r
6508 }\r
6509 void PackAddIp32(PACK *p, char *name, UINT ip32)\r
6510 {\r
6511         PackAddIp32Ex(p, name, ip32, 0, 1);\r
6512 }\r
6513 void PackAddIpEx(PACK *p, char *name, IP *ip, UINT index, UINT total)\r
6514 {\r
6515         UINT i;\r
6516         bool b = false;\r
6517         char tmp[MAX_PATH];\r
6518         // 引数チェック\r
6519         if (p == NULL || name == NULL || ip == NULL)\r
6520         {\r
6521                 return;\r
6522         }\r
6523 \r
6524         b = IsIP6(ip);\r
6525 \r
6526         Format(tmp, sizeof(tmp), "%s@ipv6_bool", name);\r
6527         PackAddBoolEx(p, tmp, b, index, total);\r
6528 \r
6529         Format(tmp, sizeof(tmp), "%s@ipv6_array", name);\r
6530         if (b)\r
6531         {\r
6532                 PackAddDataEx(p, tmp, ip->ipv6_addr, sizeof(ip->ipv6_addr), index, total);\r
6533         }\r
6534         else\r
6535         {\r
6536                 UCHAR dummy[16];\r
6537 \r
6538                 Zero(dummy, sizeof(dummy));\r
6539 \r
6540                 PackAddDataEx(p, tmp, dummy, sizeof(dummy), index, total);\r
6541         }\r
6542 \r
6543         Format(tmp, sizeof(tmp), "%s@ipv6_scope_id", name);\r
6544         if (b)\r
6545         {\r
6546                 PackAddIntEx(p, tmp, ip->ipv6_scope_id, index, total);\r
6547         }\r
6548         else\r
6549         {\r
6550                 PackAddIntEx(p, tmp, 0, index, total);\r
6551         }\r
6552 \r
6553         i = IPToUINT(ip);\r
6554 \r
6555         if (IsBigEndian())\r
6556         {\r
6557                 i = Swap32(i);\r
6558         }\r
6559 \r
6560         PackAddIntEx(p, name, i, index, total);\r
6561 }\r
6562 void PackAddIp(PACK *p, char *name, IP *ip)\r
6563 {\r
6564         PackAddIpEx(p, name, ip, 0, 1);\r
6565 }\r
6566 \r
6567 // PACK から IP を取得\r
6568 UINT PackGetIp32Ex(PACK *p, char *name, UINT index)\r
6569 {\r
6570         IP ip;\r
6571         // 引数チェック\r
6572         if (p == NULL || name == NULL)\r
6573         {\r
6574                 return 0;\r
6575         }\r
6576 \r
6577         if (PackGetIpEx(p, name, &ip, index) == false)\r
6578         {\r
6579                 return 0;\r
6580         }\r
6581 \r
6582         return IPToUINT(&ip);\r
6583 }\r
6584 UINT PackGetIp32(PACK *p, char *name)\r
6585 {\r
6586         return PackGetIp32Ex(p, name, 0);\r
6587 }\r
6588 bool PackGetIpEx(PACK *p, char *name, IP *ip, UINT index)\r
6589 {\r
6590         UINT i;\r
6591         char tmp[MAX_PATH];\r
6592         // 引数チェック\r
6593         if (p == NULL || ip == NULL || name == NULL)\r
6594         {\r
6595                 return false;\r
6596         }\r
6597 \r
6598         Format(tmp, sizeof(tmp), "%s@ipv6_bool", name);\r
6599         if (PackGetBoolEx(p, tmp, index))\r
6600         {\r
6601                 UCHAR data[16];\r
6602                 UINT scope_id;\r
6603 \r
6604                 Zero(data, sizeof(data));\r
6605 \r
6606                 Format(tmp, sizeof(tmp), "%s@ipv6_array", name);\r
6607                 PackGetDataEx2(p, tmp, data, sizeof(data), index);\r
6608 \r
6609                 Format(tmp, sizeof(tmp), "%s@ipv6_scope_id", name);\r
6610                 scope_id = PackGetIntEx(p, tmp, index);\r
6611 \r
6612                 SetIP6(ip, data);\r
6613                 ip->ipv6_scope_id = scope_id;\r
6614         }\r
6615         else\r
6616         {\r
6617                 if (GetElement(p, name, VALUE_INT) == NULL)\r
6618                 {\r
6619                         Zero(ip, sizeof(IP));\r
6620                         return false;\r
6621                 }\r
6622 \r
6623                 i = PackGetIntEx(p, name, index);\r
6624 \r
6625                 if (IsBigEndian())\r
6626                 {\r
6627                         i = Swap32(i);\r
6628                 }\r
6629 \r
6630                 UINTToIP(ip, i);\r
6631         }\r
6632 \r
6633         return true;\r
6634 }\r
6635 bool PackGetIp(PACK *p, char *name, IP *ip)\r
6636 {\r
6637         return PackGetIpEx(p, name, ip, 0);\r
6638 }\r
6639 \r
6640 // PACK から整数を取得\r
6641 UINT PackGetInt(PACK *p, char *name)\r
6642 {\r
6643         return PackGetIntEx(p, name, 0);\r
6644 }\r
6645 UINT PackGetIntEx(PACK *p, char *name, UINT index)\r
6646 {\r
6647         ELEMENT *e;\r
6648         // 引数チェック\r
6649         if (p == NULL || name == NULL)\r
6650         {\r
6651                 return 0;\r
6652         }\r
6653 \r
6654         e = GetElement(p, name, VALUE_INT);\r
6655         if (e == NULL)\r
6656         {\r
6657                 return 0;\r
6658         }\r
6659         return GetIntValue(e, index);\r
6660 }\r
6661 \r
6662 // PACK から Unicode 文字列を取得\r
6663 bool PackGetUniStr(PACK *p, char *name, wchar_t *unistr, UINT size)\r
6664 {\r
6665         return PackGetUniStrEx(p, name, unistr, size, 0);\r
6666 }\r
6667 bool PackGetUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT size, UINT index)\r
6668 {\r
6669         ELEMENT *e;\r
6670         // 引数チェック\r
6671         if (p == NULL || name == NULL || unistr == NULL || size == 0)\r
6672         {\r
6673                 return false;\r
6674         }\r
6675 \r
6676         unistr[0] = 0;\r
6677 \r
6678         e = GetElement(p, name, VALUE_UNISTR);\r
6679         if (e == NULL)\r
6680         {\r
6681                 return false;\r
6682         }\r
6683         UniStrCpy(unistr, size, GetUniStrValue(e, index));\r
6684         return true;\r
6685 }\r
6686 \r
6687 // PACK から文字列を取得\r
6688 bool PackGetStr(PACK *p, char *name, char *str, UINT size)\r
6689 {\r
6690         return PackGetStrEx(p, name, str, size, 0);\r
6691 }\r
6692 bool PackGetStrEx(PACK *p, char *name, char *str, UINT size, UINT index)\r
6693 {\r
6694         ELEMENT *e;\r
6695         // 引数チェック\r
6696         if (p == NULL || name == NULL || str == NULL || size == 0)\r
6697         {\r
6698                 return false;\r
6699         }\r
6700 \r
6701         str[0] = 0;\r
6702 \r
6703         e = GetElement(p, name, VALUE_STR);\r
6704         if (e == NULL)\r
6705         {\r
6706                 return false;\r
6707         }\r
6708 \r
6709         StrCpy(str, size, GetStrValue(e, index));\r
6710         return true;\r
6711 }\r
6712 \r
6713 // バッファを PACK に追加 (配列)\r
6714 void PackAddBufEx(PACK *p, char *name, BUF *b, UINT index, UINT total)\r
6715 {\r
6716         // 引数チェック\r
6717         if (p == NULL || name == NULL || b == NULL || total == 0)\r
6718         {\r
6719                 return;\r
6720         }\r
6721 \r
6722         PackAddDataEx(p, name, b->Buf, b->Size, index, total);\r
6723 }\r
6724 \r
6725 // データを PACK に追加 (配列)\r
6726 void PackAddDataEx(PACK *p, char *name, void *data, UINT size, UINT index, UINT total)\r
6727 {\r
6728         VALUE *v;\r
6729         ELEMENT *e;\r
6730         // 引数チェック\r
6731         if (p == NULL || data == NULL || name == NULL || total == 0)\r
6732         {\r
6733                 return;\r
6734         }\r
6735 \r
6736         v = NewDataValue(data, size);\r
6737         e = GetElement(p, name, VALUE_DATA);\r
6738         if (e != NULL)\r
6739         {\r
6740                 if (e->num_value <= total)\r
6741                 {\r
6742                         e->values[index] = v;\r
6743                 }\r
6744                 else\r
6745                 {\r
6746                         FreeValue(v, VALUE_DATA);\r
6747                 }\r
6748         }\r
6749         else\r
6750         {\r
6751                 e = ZeroMallocEx(sizeof(ELEMENT), true);\r
6752                 StrCpy(e->name, sizeof(e->name), name);\r
6753                 e->num_value = total;\r
6754                 e->type = VALUE_DATA;\r
6755                 e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);\r
6756                 e->values[index] = v;\r
6757                 AddElement(p, e);\r
6758         }\r
6759 }\r
6760 \r
6761 // バッファを PACK に追加\r
6762 void PackAddBuf(PACK *p, char *name, BUF *b)\r
6763 {\r
6764         // 引数チェック\r
6765         if (p == NULL || name == NULL || b == NULL)\r
6766         {\r
6767                 return;\r
6768         }\r
6769 \r
6770         PackAddData(p, name, b->Buf, b->Size);\r
6771 }\r
6772 \r
6773 // データを PACK に追加\r
6774 void PackAddData(PACK *p, char *name, void *data, UINT size)\r
6775 {\r
6776         VALUE *v;\r
6777         // 引数チェック\r
6778         if (p == NULL || data == NULL || name == NULL)\r
6779         {\r
6780                 return;\r
6781         }\r
6782 \r
6783         v = NewDataValue(data, size);\r
6784         AddElement(p, NewElement(name, VALUE_DATA, 1, &v));\r
6785 }\r
6786 \r
6787 // 64 bit 整数を PACK に追加 (配列)\r
6788 void PackAddInt64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total)\r
6789 {\r
6790         VALUE *v;\r
6791         ELEMENT *e;\r
6792         // 引数チェック\r
6793         if (p == NULL || name == NULL || total == 0)\r
6794         {\r
6795                 return;\r
6796         }\r
6797 \r
6798         v = NewInt64Value(i);\r
6799         e = GetElement(p, name, VALUE_INT64);\r
6800         if (e != NULL)\r
6801         {\r
6802                 if (e->num_value <= total)\r
6803                 {\r
6804                         e->values[index] = v;\r
6805                 }\r
6806                 else\r
6807                 {\r
6808                         FreeValue(v, VALUE_INT64);\r
6809                 }\r
6810         }\r
6811         else\r
6812         {\r
6813                 e = ZeroMallocEx(sizeof(ELEMENT), true);\r
6814                 StrCpy(e->name, sizeof(e->name), name);\r
6815                 e->num_value = total;\r
6816                 e->type = VALUE_INT64;\r
6817                 e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);\r
6818                 e->values[index] = v;\r
6819                 AddElement(p, e);\r
6820         }\r
6821 }\r
6822 \r
6823 // 整数を PACK に追加 (配列)\r
6824 void PackAddIntEx(PACK *p, char *name, UINT i, UINT index, UINT total)\r
6825 {\r
6826         VALUE *v;\r
6827         ELEMENT *e;\r
6828         // 引数チェック\r
6829         if (p == NULL || name == NULL || total == 0)\r
6830         {\r
6831                 return;\r
6832         }\r
6833 \r
6834         v = NewIntValue(i);\r
6835         e = GetElement(p, name, VALUE_INT);\r
6836         if (e != NULL)\r
6837         {\r
6838                 if (e->num_value <= total)\r
6839                 {\r
6840                         e->values[index] = v;\r
6841                 }\r
6842                 else\r
6843                 {\r
6844                         FreeValue(v, VALUE_INT);\r
6845                 }\r
6846         }\r
6847         else\r
6848         {\r
6849                 e = ZeroMallocEx(sizeof(ELEMENT), true);\r
6850                 StrCpy(e->name, sizeof(e->name), name);\r
6851                 e->num_value = total;\r
6852                 e->type = VALUE_INT;\r
6853                 e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);\r
6854                 e->values[index] = v;\r
6855                 AddElement(p, e);\r
6856         }\r
6857 }\r
6858 \r
6859 // 64 bit 整数を PACK に追加\r
6860 void PackAddInt64(PACK *p, char *name, UINT64 i)\r
6861 {\r
6862         VALUE *v;\r
6863         // 引数チェック\r
6864         if (p == NULL || name == NULL)\r
6865         {\r
6866                 return;\r
6867         }\r
6868 \r
6869         v = NewInt64Value(i);\r
6870         AddElement(p, NewElement(name, VALUE_INT64, 1, &v));\r
6871 }\r
6872 \r
6873 // 個数を PACK に追加\r
6874 void PackAddNum(PACK *p, char *name, UINT num)\r
6875 {\r
6876         PackAddInt(p, name, num);\r
6877 }\r
6878 \r
6879 // 整数を PACK に追加\r
6880 void PackAddInt(PACK *p, char *name, UINT i)\r
6881 {\r
6882         VALUE *v;\r
6883         // 引数チェック\r
6884         if (p == NULL || name == NULL)\r
6885         {\r
6886                 return;\r
6887         }\r
6888 \r
6889         v = NewIntValue(i);\r
6890         AddElement(p, NewElement(name, VALUE_INT, 1, &v));\r
6891 }\r
6892 \r
6893 // Unicode 文字列を PACK に追加 (配列)\r
6894 void PackAddUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT index, UINT total)\r
6895 {\r
6896         VALUE *v;\r
6897         ELEMENT *e;\r
6898         // 引数チェック\r
6899         if (p == NULL || name == NULL || unistr == NULL || total == 0)\r
6900         {\r
6901                 return;\r
6902         }\r
6903 \r
6904         v = NewUniStrValue(unistr);\r
6905         e = GetElement(p, name, VALUE_UNISTR);\r
6906         if (e != NULL)\r
6907         {\r
6908                 if (e->num_value <= total)\r
6909                 {\r
6910                         e->values[index] = v;\r
6911                 }\r
6912                 else\r
6913                 {\r
6914                         FreeValue(v, VALUE_UNISTR);\r
6915                 }\r
6916         }\r
6917         else\r
6918         {\r
6919                 e = ZeroMallocEx(sizeof(ELEMENT), true);\r
6920                 StrCpy(e->name, sizeof(e->name), name);\r
6921                 e->num_value = total;\r
6922                 e->type = VALUE_UNISTR;\r
6923                 e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);\r
6924                 e->values[index] = v;\r
6925                 AddElement(p, e);\r
6926         }\r
6927 }\r
6928 \r
6929 // Unicode 文字列を PACK に追加\r
6930 void PackAddUniStr(PACK *p, char *name, wchar_t *unistr)\r
6931 {\r
6932         VALUE *v;\r
6933         // 引数チェック\r
6934         if (p == NULL || name == NULL || unistr == NULL)\r
6935         {\r
6936                 return;\r
6937         }\r
6938 \r
6939         v = NewUniStrValue(unistr);\r
6940         AddElement(p, NewElement(name, VALUE_UNISTR, 1, &v));\r
6941 }\r
6942 \r
6943 // 文字列を PACK に追加 (配列)\r
6944 void PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total)\r
6945 {\r
6946         VALUE *v;\r
6947         ELEMENT *e;\r
6948         // 引数チェック\r
6949         if (p == NULL || name == NULL || str == NULL || total == 0)\r
6950         {\r
6951                 return;\r
6952         }\r
6953 \r
6954         v = NewStrValue(str);\r
6955         e = GetElement(p, name, VALUE_STR);\r
6956         if (e != NULL)\r
6957         {\r
6958                 if (e->num_value <= total)\r
6959                 {\r
6960                         e->values[index] = v;\r
6961                 }\r
6962                 else\r
6963                 {\r
6964                         FreeValue(v, VALUE_STR);\r
6965                 }\r
6966         }\r
6967         else\r
6968         {\r
6969                 e = ZeroMallocEx(sizeof(ELEMENT), true);\r
6970                 StrCpy(e->name, sizeof(e->name), name);\r
6971                 e->num_value = total;\r
6972                 e->type = VALUE_STR;\r
6973                 e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);\r
6974                 e->values[index] = v;\r
6975                 AddElement(p, e);\r
6976         }\r
6977 }\r
6978 \r
6979 // 文字列を PACK に追加\r
6980 void PackAddStr(PACK *p, char *name, char *str)\r
6981 {\r
6982         VALUE *v;\r
6983         // 引数チェック\r
6984         if (p == NULL || name == NULL || str == NULL)\r
6985         {\r
6986                 return;\r
6987         }\r
6988 \r
6989         v = NewStrValue(str);\r
6990         AddElement(p, NewElement(name, VALUE_STR, 1, &v));\r
6991 }\r
6992 \r
6993 // RC4 キーペアを生成\r
6994 void GenerateRC4KeyPair(RC4_KEY_PAIR *k)\r
6995 {\r
6996         // 引数チェック\r
6997         if (k == NULL)\r
6998         {\r
6999                 return;\r
7000         }\r
7001 \r
7002         Rand(k->ClientToServerKey, sizeof(k->ClientToServerKey));\r
7003         Rand(k->ServerToClientKey, sizeof(k->ServerToClientKey));\r
7004 }\r
7005 \r